/*
 * 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 */
