[BACK]Return to sqr_basecase.asm CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / x86 / k6

Annotation of OpenXM_contrib/gmp/mpn/x86/k6/sqr_basecase.asm, Revision 1.1

1.1     ! maekawa     1: dnl  AMD K6 mpn_sqr_basecase -- square an mpn number.
        !             2: dnl
        !             3: dnl  K6: approx 4.7 cycles per cross product, or 9.2 cycles per triangular
        !             4: dnl  product (measured on the speed difference between 17 and 33 limbs,
        !             5: dnl  which is roughly the Karatsuba recursing range).
        !             6:
        !             7:
        !             8: dnl  Copyright (C) 1999, 2000 Free Software Foundation, Inc.
        !             9: dnl
        !            10: dnl  This file is part of the GNU MP Library.
        !            11: dnl
        !            12: dnl  The GNU MP Library is free software; you can redistribute it and/or
        !            13: dnl  modify it under the terms of the GNU Lesser General Public License as
        !            14: dnl  published by the Free Software Foundation; either version 2.1 of the
        !            15: dnl  License, or (at your option) any later version.
        !            16: dnl
        !            17: dnl  The GNU MP Library is distributed in the hope that it will be useful,
        !            18: dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            19: dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            20: dnl  Lesser General Public License for more details.
        !            21: dnl
        !            22: dnl  You should have received a copy of the GNU Lesser General Public
        !            23: dnl  License along with the GNU MP Library; see the file COPYING.LIB.  If
        !            24: dnl  not, write to the Free Software Foundation, Inc., 59 Temple Place -
        !            25: dnl  Suite 330, Boston, MA 02111-1307, USA.
        !            26:
        !            27:
        !            28: include(`../config.m4')
        !            29:
        !            30:
        !            31: dnl  KARATSUBA_SQR_THRESHOLD_MAX is the maximum KARATSUBA_SQR_THRESHOLD this
        !            32: dnl  code supports.  This value is used only by the tune program to know
        !            33: dnl  what it can go up to.  (An attempt to compile with a bigger value will
        !            34: dnl  trigger some m4_assert()s in the code, making the build fail.)
        !            35: dnl
        !            36: dnl  The value is determined by requiring the displacements in the unrolled
        !            37: dnl  addmul to fit in single bytes.  This means a maximum UNROLL_COUNT of
        !            38: dnl  63, giving a maximum KARATSUBA_SQR_THRESHOLD of 66.
        !            39:
        !            40: deflit(KARATSUBA_SQR_THRESHOLD_MAX, 66)
        !            41:
        !            42:
        !            43: dnl  Allow a value from the tune program to override config.m4.
        !            44:
        !            45: ifdef(`KARATSUBA_SQR_THRESHOLD_OVERRIDE',
        !            46: `define(`KARATSUBA_SQR_THRESHOLD',KARATSUBA_SQR_THRESHOLD_OVERRIDE)')
        !            47:
        !            48:
        !            49: dnl  UNROLL_COUNT is the number of code chunks in the unrolled addmul.  The
        !            50: dnl  number required is determined by KARATSUBA_SQR_THRESHOLD, since
        !            51: dnl  mpn_sqr_basecase only needs to handle sizes < KARATSUBA_SQR_THRESHOLD.
        !            52: dnl
        !            53: dnl  The first addmul is the biggest, and this takes the second least
        !            54: dnl  significant limb and multiplies it by the third least significant and
        !            55: dnl  up.  Hence for a maximum operand size of KARATSUBA_SQR_THRESHOLD-1
        !            56: dnl  limbs, UNROLL_COUNT needs to be KARATSUBA_SQR_THRESHOLD-3.
        !            57:
        !            58: m4_config_gmp_mparam(`KARATSUBA_SQR_THRESHOLD')
        !            59: deflit(UNROLL_COUNT, eval(KARATSUBA_SQR_THRESHOLD-3))
        !            60:
        !            61:
        !            62: C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
        !            63: C
        !            64: C The algorithm is essentially the same as mpn/generic/sqr_basecase.c, but a
        !            65: C lot of function call overheads are avoided, especially when the given size
        !            66: C is small.
        !            67: C
        !            68: C The code size might look a bit excessive, but not all of it is executed
        !            69: C and so won't fill up the code cache.  The 1x1, 2x2 and 3x3 special cases
        !            70: C clearly apply only to those sizes; mid sizes like 10x10 only need part of
        !            71: C the unrolled addmul; and big sizes like 35x35 that do need all of it will
        !            72: C at least be getting value for money, because 35x35 spends something like
        !            73: C 5780 cycles here.
        !            74: C
        !            75: C Different values of UNROLL_COUNT give slightly different speeds, between
        !            76: C 9.0 and 9.2 c/tri-prod measured on the difference between 17 and 33 limbs.
        !            77: C This isn't a big difference, but it's presumably some alignment effect
        !            78: C which if understood could give a simple speedup.
        !            79:
        !            80: defframe(PARAM_SIZE,12)
        !            81: defframe(PARAM_SRC, 8)
        !            82: defframe(PARAM_DST, 4)
        !            83:
        !            84:        .text
        !            85:        ALIGN(32)
        !            86: PROLOGUE(mpn_sqr_basecase)
        !            87: deflit(`FRAME',0)
        !            88:
        !            89:        movl    PARAM_SIZE, %ecx
        !            90:        movl    PARAM_SRC, %eax
        !            91:
        !            92:        cmpl    $2, %ecx
        !            93:        je      L(two_limbs)
        !            94:
        !            95:        movl    PARAM_DST, %edx
        !            96:        ja      L(three_or_more)
        !            97:
        !            98:
        !            99: C -----------------------------------------------------------------------------
        !           100: C one limb only
        !           101:        C eax   src
        !           102:        C ebx
        !           103:        C ecx   size
        !           104:        C edx   dst
        !           105:
        !           106:        movl    (%eax), %eax
        !           107:        movl    %edx, %ecx
        !           108:
        !           109:        mull    %eax
        !           110:
        !           111:        movl    %eax, (%ecx)
        !           112:        movl    %edx, 4(%ecx)
        !           113:        ret
        !           114:
        !           115:
        !           116: C -----------------------------------------------------------------------------
        !           117:        ALIGN(16)
        !           118: L(two_limbs):
        !           119:        C eax   src
        !           120:        C ebx
        !           121:        C ecx   size
        !           122:        C edx   dst
        !           123:
        !           124:        pushl   %ebx
        !           125:        movl    %eax, %ebx      C src
        !           126: deflit(`FRAME',4)
        !           127:
        !           128:        movl    (%ebx), %eax
        !           129:        movl    PARAM_DST, %ecx
        !           130:
        !           131:        mull    %eax            C src[0]^2
        !           132:
        !           133:        movl    %eax, (%ecx)
        !           134:        movl    4(%ebx), %eax
        !           135:
        !           136:        movl    %edx, 4(%ecx)
        !           137:
        !           138:        mull    %eax            C src[1]^2
        !           139:
        !           140:        movl    %eax, 8(%ecx)
        !           141:        movl    (%ebx), %eax
        !           142:
        !           143:        movl    %edx, 12(%ecx)
        !           144:        movl    4(%ebx), %edx
        !           145:
        !           146:        mull    %edx            C src[0]*src[1]
        !           147:
        !           148:        addl    %eax, 4(%ecx)
        !           149:
        !           150:        adcl    %edx, 8(%ecx)
        !           151:        adcl    $0, 12(%ecx)
        !           152:
        !           153:        popl    %ebx
        !           154:        addl    %eax, 4(%ecx)
        !           155:
        !           156:        adcl    %edx, 8(%ecx)
        !           157:        adcl    $0, 12(%ecx)
        !           158:
        !           159:        ret
        !           160:
        !           161:
        !           162: C -----------------------------------------------------------------------------
        !           163: L(three_or_more):
        !           164: deflit(`FRAME',0)
        !           165:        cmpl    $4, %ecx
        !           166:        jae     L(four_or_more)
        !           167:
        !           168:
        !           169: C -----------------------------------------------------------------------------
        !           170: C three limbs
        !           171:        C eax   src
        !           172:        C ecx   size
        !           173:        C edx   dst
        !           174:
        !           175:        pushl   %ebx
        !           176:        movl    %eax, %ebx      C src
        !           177:
        !           178:        movl    (%ebx), %eax
        !           179:        movl    %edx, %ecx      C dst
        !           180:
        !           181:        mull    %eax            C src[0] ^ 2
        !           182:
        !           183:        movl    %eax, (%ecx)
        !           184:        movl    4(%ebx), %eax
        !           185:
        !           186:        movl    %edx, 4(%ecx)
        !           187:        pushl   %esi
        !           188:
        !           189:        mull    %eax            C src[1] ^ 2
        !           190:
        !           191:        movl    %eax, 8(%ecx)
        !           192:        movl    8(%ebx), %eax
        !           193:
        !           194:        movl    %edx, 12(%ecx)
        !           195:        pushl   %edi
        !           196:
        !           197:        mull    %eax            C src[2] ^ 2
        !           198:
        !           199:        movl    %eax, 16(%ecx)
        !           200:        movl    (%ebx), %eax
        !           201:
        !           202:        movl    %edx, 20(%ecx)
        !           203:        movl    4(%ebx), %edx
        !           204:
        !           205:        mull    %edx            C src[0] * src[1]
        !           206:
        !           207:        movl    %eax, %esi
        !           208:        movl    (%ebx), %eax
        !           209:
        !           210:        movl    %edx, %edi
        !           211:        movl    8(%ebx), %edx
        !           212:
        !           213:        pushl   %ebp
        !           214:        xorl    %ebp, %ebp
        !           215:
        !           216:        mull    %edx            C src[0] * src[2]
        !           217:
        !           218:        addl    %eax, %edi
        !           219:        movl    4(%ebx), %eax
        !           220:
        !           221:        adcl    %edx, %ebp
        !           222:
        !           223:        movl    8(%ebx), %edx
        !           224:
        !           225:        mull    %edx            C src[1] * src[2]
        !           226:
        !           227:        addl    %eax, %ebp
        !           228:
        !           229:        adcl    $0, %edx
        !           230:
        !           231:
        !           232:        C eax   will be dst[5]
        !           233:        C ebx
        !           234:        C ecx   dst
        !           235:        C edx   dst[4]
        !           236:        C esi   dst[1]
        !           237:        C edi   dst[2]
        !           238:        C ebp   dst[3]
        !           239:
        !           240:        xorl    %eax, %eax
        !           241:        addl    %esi, %esi
        !           242:        adcl    %edi, %edi
        !           243:        adcl    %ebp, %ebp
        !           244:        adcl    %edx, %edx
        !           245:        adcl    $0, %eax
        !           246:
        !           247:        addl    %esi, 4(%ecx)
        !           248:        adcl    %edi, 8(%ecx)
        !           249:        adcl    %ebp, 12(%ecx)
        !           250:
        !           251:        popl    %ebp
        !           252:        popl    %edi
        !           253:
        !           254:        adcl    %edx, 16(%ecx)
        !           255:
        !           256:        popl    %esi
        !           257:        popl    %ebx
        !           258:
        !           259:        adcl    %eax, 20(%ecx)
        !           260:        ASSERT(nc)
        !           261:
        !           262:        ret
        !           263:
        !           264:
        !           265: C -----------------------------------------------------------------------------
        !           266:
        !           267: defframe(SAVE_EBX,   -4)
        !           268: defframe(SAVE_ESI,   -8)
        !           269: defframe(SAVE_EDI,   -12)
        !           270: defframe(SAVE_EBP,   -16)
        !           271: defframe(VAR_COUNTER,-20)
        !           272: defframe(VAR_JMP,    -24)
        !           273: deflit(STACK_SPACE, 24)
        !           274:
        !           275:        ALIGN(16)
        !           276: L(four_or_more):
        !           277:
        !           278:        C eax   src
        !           279:        C ebx
        !           280:        C ecx   size
        !           281:        C edx   dst
        !           282:        C esi
        !           283:        C edi
        !           284:        C ebp
        !           285:
        !           286: C First multiply src[0]*src[1..size-1] and store at dst[1..size].
        !           287: C
        !           288: C A test was done calling mpn_mul_1 here to get the benefit of its unrolled
        !           289: C loop, but this was only a tiny speedup; at 35 limbs it took 24 cycles off
        !           290: C a 5780 cycle operation, which is not surprising since the loop here is 8
        !           291: C c/l and mpn_mul_1 is 6.25 c/l.
        !           292:
        !           293:        subl    $STACK_SPACE, %esp      deflit(`FRAME',STACK_SPACE)
        !           294:
        !           295:        movl    %edi, SAVE_EDI
        !           296:        leal    4(%edx), %edi
        !           297:
        !           298:        movl    %ebx, SAVE_EBX
        !           299:        leal    4(%eax), %ebx
        !           300:
        !           301:        movl    %esi, SAVE_ESI
        !           302:        xorl    %esi, %esi
        !           303:
        !           304:        movl    %ebp, SAVE_EBP
        !           305:
        !           306:        C eax
        !           307:        C ebx   src+4
        !           308:        C ecx   size
        !           309:        C edx
        !           310:        C esi
        !           311:        C edi   dst+4
        !           312:        C ebp
        !           313:
        !           314:        movl    (%eax), %ebp    C multiplier
        !           315:        leal    -1(%ecx), %ecx  C size-1, and pad to a 16 byte boundary
        !           316:
        !           317:
        !           318:        ALIGN(16)
        !           319: L(mul_1):
        !           320:        C eax   scratch
        !           321:        C ebx   src ptr
        !           322:        C ecx   counter
        !           323:        C edx   scratch
        !           324:        C esi   carry
        !           325:        C edi   dst ptr
        !           326:        C ebp   multiplier
        !           327:
        !           328:        movl    (%ebx), %eax
        !           329:        addl    $4, %ebx
        !           330:
        !           331:        mull    %ebp
        !           332:
        !           333:        addl    %esi, %eax
        !           334:        movl    $0, %esi
        !           335:
        !           336:        adcl    %edx, %esi
        !           337:
        !           338:        movl    %eax, (%edi)
        !           339:        addl    $4, %edi
        !           340:
        !           341:        loop    L(mul_1)
        !           342:
        !           343:
        !           344: C Addmul src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
        !           345: C
        !           346: C The last two addmuls, which are the bottom right corner of the product
        !           347: C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
        !           348: C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
        !           349: C cases that need to be done.
        !           350: C
        !           351: C The unrolled code is the same as mpn_addmul_1(), see that routine for some
        !           352: C comments.
        !           353: C
        !           354: C VAR_COUNTER is the outer loop, running from -(size-4) to -1, inclusive.
        !           355: C
        !           356: C VAR_JMP is the computed jump into the unrolled code, stepped by one code
        !           357: C chunk each outer loop.
        !           358: C
        !           359: C K6 doesn't do any branch prediction on indirect jumps, which is good
        !           360: C actually because it's a different target each time.  The unrolled addmul
        !           361: C is about 3 cycles/limb faster than a simple loop, so the 6 cycle cost of
        !           362: C the indirect jump is quickly recovered.
        !           363:
        !           364:
        !           365: dnl  This value is also implicitly encoded in a shift and add.
        !           366: dnl
        !           367: deflit(CODE_BYTES_PER_LIMB, 15)
        !           368:
        !           369: dnl  With the unmodified &src[size] and &dst[size] pointers, the
        !           370: dnl  displacements in the unrolled code fit in a byte for UNROLL_COUNT
        !           371: dnl  values up to 31.  Above that an offset must be added to them.
        !           372: dnl
        !           373: deflit(OFFSET,
        !           374: ifelse(eval(UNROLL_COUNT>31),1,
        !           375: eval((UNROLL_COUNT-31)*4),
        !           376: 0))
        !           377:
        !           378:        C eax
        !           379:        C ebx   &src[size]
        !           380:        C ecx
        !           381:        C edx
        !           382:        C esi   carry
        !           383:        C edi   &dst[size]
        !           384:        C ebp
        !           385:
        !           386:        movl    PARAM_SIZE, %ecx
        !           387:        movl    %esi, (%edi)
        !           388:
        !           389:        subl    $4, %ecx
        !           390:        jz      L(corner)
        !           391:
        !           392:        movl    %ecx, %edx
        !           393: ifelse(OFFSET,0,,
        !           394: `      subl    $OFFSET, %ebx')
        !           395:
        !           396:        shll    $4, %ecx
        !           397: ifelse(OFFSET,0,,
        !           398: `      subl    $OFFSET, %edi')
        !           399:
        !           400:        negl    %ecx
        !           401:
        !           402: ifdef(`PIC',`
        !           403:        call    L(pic_calc)
        !           404: L(here):
        !           405: ',`
        !           406:        leal    L(unroll_inner_end)-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
        !           407: ')
        !           408:        negl    %edx
        !           409:
        !           410:
        !           411:        C The calculated jump mustn't be before the start of the available
        !           412:        C code.  This is the limitation UNROLL_COUNT puts on the src operand
        !           413:        C size, but checked here using the jump address directly.
        !           414:        C
        !           415:        ASSERT(ae,`
        !           416:        movl_text_address( L(unroll_inner_start), %eax)
        !           417:        cmpl    %eax, %ecx
        !           418:        ')
        !           419:
        !           420:
        !           421: C -----------------------------------------------------------------------------
        !           422:        ALIGN(16)
        !           423: L(unroll_outer_top):
        !           424:        C eax
        !           425:        C ebx   &src[size], constant
        !           426:        C ecx   VAR_JMP
        !           427:        C edx   VAR_COUNTER, limbs, negative
        !           428:        C esi   high limb to store
        !           429:        C edi   dst ptr, high of last addmul
        !           430:        C ebp
        !           431:
        !           432:        movl    -12+OFFSET(%ebx,%edx,4), %ebp   C multiplier
        !           433:        movl    %edx, VAR_COUNTER
        !           434:
        !           435:        movl    -8+OFFSET(%ebx,%edx,4), %eax    C first limb of multiplicand
        !           436:
        !           437:        mull    %ebp
        !           438:
        !           439:        testb   $1, %cl
        !           440:
        !           441:        movl    %edx, %esi      C high carry
        !           442:        movl    %ecx, %edx      C jump
        !           443:
        !           444:        movl    %eax, %ecx      C low carry
        !           445:        leal    CODE_BYTES_PER_LIMB(%edx), %edx
        !           446:
        !           447:        movl    %edx, VAR_JMP
        !           448:        leal    4(%edi), %edi
        !           449:
        !           450:        C A branch-free version of this using some xors was found to be a
        !           451:        C touch slower than just a conditional jump, despite the jump
        !           452:        C switching between taken and not taken on every loop.
        !           453:
        !           454: ifelse(eval(UNROLL_COUNT%2),0,
        !           455:        jz,jnz) L(unroll_noswap)
        !           456:        movl    %esi, %eax      C high,low carry other way around
        !           457:
        !           458:        movl    %ecx, %esi
        !           459:        movl    %eax, %ecx
        !           460: L(unroll_noswap):
        !           461:
        !           462:        jmp     *%edx
        !           463:
        !           464:
        !           465:        C Must be on an even address here so the low bit of the jump address
        !           466:        C will indicate which way around ecx/esi should start.
        !           467:        C
        !           468:        C An attempt was made at padding here to get the end of the unrolled
        !           469:        C code to come out on a good alignment, to save padding before
        !           470:        C L(corner).  This worked, but turned out to run slower than just an
        !           471:        C ALIGN(2).  The reason for this is not clear, it might be related
        !           472:        C to the different speeds on different UNROLL_COUNTs noted above.
        !           473:
        !           474:        ALIGN(2)
        !           475:
        !           476: L(unroll_inner_start):
        !           477:        C eax   scratch
        !           478:        C ebx   src
        !           479:        C ecx   carry low
        !           480:        C edx   scratch
        !           481:        C esi   carry high
        !           482:        C edi   dst
        !           483:        C ebp   multiplier
        !           484:        C
        !           485:        C 15 code bytes each limb
        !           486:        C ecx/esi swapped on each chunk
        !           487:
        !           488: forloop(`i', UNROLL_COUNT, 1, `
        !           489:        deflit(`disp_src', eval(-i*4 + OFFSET))
        !           490:        deflit(`disp_dst', eval(disp_src - 4))
        !           491:
        !           492:        m4_assert(`disp_src>=-128 && disp_src<128')
        !           493:        m4_assert(`disp_dst>=-128 && disp_dst<128')
        !           494:
        !           495: ifelse(eval(i%2),0,`
        !           496: Zdisp( movl,   disp_src,(%ebx), %eax)
        !           497:        mull    %ebp
        !           498: Zdisp( addl,   %esi, disp_dst,(%edi))
        !           499:        adcl    %eax, %ecx
        !           500:        movl    %edx, %esi
        !           501:        jadcl0( %esi)
        !           502: ',`
        !           503:        dnl  this one comes out last
        !           504: Zdisp( movl,   disp_src,(%ebx), %eax)
        !           505:        mull    %ebp
        !           506: Zdisp( addl,   %ecx, disp_dst,(%edi))
        !           507:        adcl    %eax, %esi
        !           508:        movl    %edx, %ecx
        !           509:        jadcl0( %ecx)
        !           510: ')
        !           511: ')
        !           512: L(unroll_inner_end):
        !           513:
        !           514:        addl    %esi, -4+OFFSET(%edi)
        !           515:
        !           516:        movl    VAR_COUNTER, %edx
        !           517:        jadcl0( %ecx)
        !           518:
        !           519:        movl    %ecx, m4_empty_if_zero(OFFSET)(%edi)
        !           520:        movl    VAR_JMP, %ecx
        !           521:
        !           522:        incl    %edx
        !           523:        jnz     L(unroll_outer_top)
        !           524:
        !           525:
        !           526: ifelse(OFFSET,0,,`
        !           527:        addl    $OFFSET, %ebx
        !           528:        addl    $OFFSET, %edi
        !           529: ')
        !           530:
        !           531:
        !           532: C -----------------------------------------------------------------------------
        !           533:        ALIGN(16)
        !           534: L(corner):
        !           535:        C ebx   &src[size]
        !           536:        C edi   &dst[2*size-5]
        !           537:
        !           538:        movl    -12(%ebx), %ebp
        !           539:
        !           540:        movl    -8(%ebx), %eax
        !           541:        movl    %eax, %ecx
        !           542:
        !           543:        mull    %ebp
        !           544:
        !           545:        addl    %eax, -4(%edi)
        !           546:        adcl    $0, %edx
        !           547:
        !           548:        movl    -4(%ebx), %eax
        !           549:        movl    %edx, %esi
        !           550:        movl    %eax, %ebx
        !           551:
        !           552:        mull    %ebp
        !           553:
        !           554:        addl    %esi, %eax
        !           555:        adcl    $0, %edx
        !           556:
        !           557:        addl    %eax, (%edi)
        !           558:        adcl    $0, %edx
        !           559:
        !           560:        movl    %edx, %esi
        !           561:        movl    %ebx, %eax
        !           562:
        !           563:        mull    %ecx
        !           564:
        !           565:        addl    %esi, %eax
        !           566:        movl    %eax, 4(%edi)
        !           567:
        !           568:        adcl    $0, %edx
        !           569:
        !           570:        movl    %edx, 8(%edi)
        !           571:
        !           572:
        !           573: C -----------------------------------------------------------------------------
        !           574: C Left shift of dst[1..2*size-2], the bit shifted out becomes dst[2*size-1].
        !           575: C The loop measures about 6 cycles/iteration, though it looks like it should
        !           576: C decode in 5.
        !           577:
        !           578: L(lshift_start):
        !           579:        movl    PARAM_SIZE, %ecx
        !           580:
        !           581:        movl    PARAM_DST, %edi
        !           582:        subl    $1, %ecx                C size-1 and clear carry
        !           583:
        !           584:        movl    PARAM_SRC, %ebx
        !           585:        movl    %ecx, %edx
        !           586:
        !           587:        xorl    %eax, %eax              C ready for adcl
        !           588:
        !           589:
        !           590:        ALIGN(16)
        !           591: L(lshift):
        !           592:        C eax
        !           593:        C ebx   src (for later use)
        !           594:        C ecx   counter, decrementing
        !           595:        C edx   size-1 (for later use)
        !           596:        C esi
        !           597:        C edi   dst, incrementing
        !           598:        C ebp
        !           599:
        !           600:        rcll    4(%edi)
        !           601:        rcll    8(%edi)
        !           602:        leal    8(%edi), %edi
        !           603:        loop    L(lshift)
        !           604:
        !           605:
        !           606:        adcl    %eax, %eax
        !           607:
        !           608:        movl    %eax, 4(%edi)           C dst most significant limb
        !           609:        movl    (%ebx), %eax            C src[0]
        !           610:
        !           611:        leal    4(%ebx,%edx,4), %ebx    C &src[size]
        !           612:        subl    %edx, %ecx              C -(size-1)
        !           613:
        !           614:
        !           615: C -----------------------------------------------------------------------------
        !           616: C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
        !           617: C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
        !           618: C low limb of src[0]^2.
        !           619:
        !           620:
        !           621:        mull    %eax
        !           622:
        !           623:        movl    %eax, (%edi,%ecx,8)     C dst[0]
        !           624:
        !           625:
        !           626:        ALIGN(16)
        !           627: L(diag):
        !           628:        C eax   scratch
        !           629:        C ebx   &src[size]
        !           630:        C ecx   counter, negative
        !           631:        C edx   carry
        !           632:        C esi   scratch
        !           633:        C edi   dst[2*size-2]
        !           634:        C ebp
        !           635:
        !           636:        movl    (%ebx,%ecx,4), %eax
        !           637:        movl    %edx, %esi
        !           638:
        !           639:        mull    %eax
        !           640:
        !           641:        addl    %esi, 4(%edi,%ecx,8)
        !           642:        adcl    %eax, 8(%edi,%ecx,8)
        !           643:        adcl    $0, %edx
        !           644:
        !           645:        incl    %ecx
        !           646:        jnz     L(diag)
        !           647:
        !           648:
        !           649:        movl    SAVE_EBX, %ebx
        !           650:        movl    SAVE_ESI, %esi
        !           651:
        !           652:        addl    %edx, 4(%edi)           C dst most significant limb
        !           653:
        !           654:        movl    SAVE_EDI, %edi
        !           655:        movl    SAVE_EBP, %ebp
        !           656:        addl    $FRAME, %esp
        !           657:        ret
        !           658:
        !           659:
        !           660:
        !           661: C -----------------------------------------------------------------------------
        !           662: ifdef(`PIC',`
        !           663: L(pic_calc):
        !           664:         C See README.family about old gas bugs
        !           665:        addl    (%esp), %ecx
        !           666:        addl    $L(unroll_inner_end)-L(here)-eval(2*CODE_BYTES_PER_LIMB), %ecx
        !           667:        addl    %edx, %ecx
        !           668:        ret
        !           669: ')
        !           670:
        !           671:
        !           672: EPILOGUE()

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>