root/usr/src/lib/libc/i386/gen/_divdi3.S
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

        .file   "_divdi3.s"

#include <SYS.h>

/*
 * C support for 64-bit modulo and division.
 * GNU routines callable from C (though generated by the compiler).
 * Hand-customized compiler output - see comments for details.
 */

#if defined(__lint)

/*ARGSUSED*/
uint64_t
__udivdi3(uint64_t a, uint64_t b)
{ return (0); }

/*ARGSUSED*/
uint64_t
__umoddi3(uint64_t a, uint64_t b)
{ return (0); }

/*ARGSUSED*/
int64_t
__divdi3(int64_t a, int64_t b)
{ return (0); }

/*ARGSUSED*/
int64_t
__moddi3(int64_t a, int64_t b)
{ return (0); }

#else

/*
 * __udivdi3
 *
 * Perform division of two unsigned 64-bit quantities, returning the
 * quotient in %edx:%eax.
 */
        ENTRY(__udivdi3)
        movl    4(%esp), %eax   / x, x
        movl    8(%esp), %edx   / x, x
        pushl   16(%esp)        / y
        pushl   16(%esp)
        call    UDiv
        addl    $8, %esp
        ret
        SET_SIZE(__udivdi3)

/*
 * __umoddi3
 *
 * Perform division of two unsigned 64-bit quantities, returning the
 * remainder in %edx:%eax.
 */
        ENTRY(__umoddi3)
        subl    $12, %esp
        movl    %esp, %ecx      /, tmp65
        movl    16(%esp), %eax  / x, x
        movl    20(%esp), %edx  / x, x
        pushl   %ecx            / tmp65
        pushl   32(%esp)        / y
        pushl   32(%esp)
        call    UDivRem
        movl    12(%esp), %eax  / rem, rem
        movl    16(%esp), %edx  / rem, rem
        addl    $24, %esp
        ret
        SET_SIZE(__umoddi3)

/*
 * __divdi3
 *
 * Perform division of two signed 64-bit quantities, returning the
 * quotient in %edx:%eax.
 */
/ int64_t
/ __divdi3(int64_t x, int64_t y)
/ {
/       int             negative;
/       uint64_t        xt, yt, r;
/
/       if (x < 0) {
/               xt = -(uint64_t) x;
/               negative = 1;
/       } else {
/               xt = x;
/               negative = 0;
/       }
/       if (y < 0) {
/               yt = -(uint64_t) y;
/               negative ^= 1;
/       } else {
/               yt = y;
/       }
/       r = UDiv(xt, yt);
/       return (negative ? (int64_t) - r : r);
/ }
        ENTRY(__divdi3)
        pushl   %ebp
        pushl   %edi
        pushl   %esi
        subl    $8, %esp
        movl    28(%esp), %edx  / x, x
        testl   %edx, %edx      / x
        movl    24(%esp), %eax  / x, x
        movl    32(%esp), %esi  / y, y
        movl    36(%esp), %edi  / y, y
        js      .LL55
        xorl    %ebp, %ebp      / negative
        testl   %edi, %edi      / y
        movl    %eax, (%esp)    / x, xt
        movl    %edx, 4(%esp)   / x, xt
        movl    %esi, %eax      / y, yt
        movl    %edi, %edx      / y, yt
        js      .LL56
.LL53:
        pushl   %edx            / yt
        pushl   %eax            / yt
        movl    8(%esp), %eax   / xt, xt
        movl    12(%esp), %edx  / xt, xt
        call    UDiv
        popl    %ecx
        testl   %ebp, %ebp      / negative
        popl    %esi
        je      .LL54
        negl    %eax            / r
        adcl    $0, %edx        /, r
        negl    %edx            / r
.LL54:
        addl    $8, %esp
        popl    %esi
        popl    %edi
        popl    %ebp
        ret
        .align  16
.LL55:
        negl    %eax            / x
        adcl    $0, %edx        /, x
        negl    %edx            / x
        testl   %edi, %edi      / y
        movl    %eax, (%esp)    / x, xt
        movl    %edx, 4(%esp)   / x, xt
        movl    $1, %ebp        /, negative
        movl    %esi, %eax      / y, yt
        movl    %edi, %edx      / y, yt
        jns     .LL53
        .align  16
.LL56:
        negl    %eax            / yt
        adcl    $0, %edx        /, yt
        negl    %edx            / yt
        xorl    $1, %ebp        /, negative
        jmp     .LL53
        SET_SIZE(__divdi3)

/*
 * __moddi3
 *
 * Perform division of two signed 64-bit quantities, returning the
 * quotient in %edx:%eax.
 */
/ int64_t
/ __moddi3(int64_t x, int64_t y)
/ {
/       uint64_t        xt, yt, rem;
/
/       if (x < 0) {
/               xt = -(uint64_t) x;
/       } else {
/               xt = x;
/       }
/       if (y < 0) {
/               yt = -(uint64_t) y;
/       } else {
/               yt = y;
/       }
/       (void) UDivRem(xt, yt, &rem);
/       return (x < 0 ? (int64_t) - rem : rem);
/ }
        ENTRY(__moddi3)
        pushl   %edi
        pushl   %esi
        subl    $20, %esp
        movl    36(%esp), %ecx  / x,
        movl    32(%esp), %esi  / x,
        movl    36(%esp), %edi  / x,
        testl   %ecx, %ecx
        movl    40(%esp), %eax  / y, y
        movl    44(%esp), %edx  / y, y
        movl    %esi, (%esp)    /, xt
        movl    %edi, 4(%esp)   /, xt
        js      .LL63
        testl   %edx, %edx      / y
        movl    %eax, %esi      / y, yt
        movl    %edx, %edi      / y, yt
        js      .LL64
.LL61:
        leal    8(%esp), %eax   /, tmp66
        pushl   %eax            / tmp66
        pushl   %edi            / yt
        pushl   %esi            / yt
        movl    12(%esp), %eax  / xt, xt
        movl    16(%esp), %edx  / xt, xt
        call    UDivRem
        addl    $12, %esp
        movl    36(%esp), %edi  / x,
        testl   %edi, %edi
        movl    8(%esp), %eax   / rem, rem
        movl    12(%esp), %edx  / rem, rem
        js      .LL65
        addl    $20, %esp
        popl    %esi
        popl    %edi
        ret
        .align  16
.LL63:
        negl    %esi
        adcl    $0, %edi
        negl    %edi
        testl   %edx, %edx      / y
        movl    %esi, (%esp)    /, xt
        movl    %edi, 4(%esp)   /, xt
        movl    %eax, %esi      / y, yt
        movl    %edx, %edi      / y, yt
        jns     .LL61
        .align  16
.LL64:
        negl    %esi            / yt
        adcl    $0, %edi        /, yt
        negl    %edi            / yt
        jmp     .LL61
        .align  16
.LL65:
        negl    %eax            / rem
        adcl    $0, %edx        /, rem
        addl    $20, %esp
        popl    %esi
        negl    %edx            / rem
        popl    %edi
        ret
        SET_SIZE(__moddi3)

#endif  /* __lint */