xref: /onnv-gate/usr/src/lib/libc/i386/gen/_div64.s (revision 7298:b69e27387f74)
10Sstevel@tonic-gate/*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7298SMark.J.Nelson@Sun.COM * Common Development and Distribution License (the "License").
6*7298SMark.J.Nelson@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate/*
220Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
26*7298SMark.J.Nelson@Sun.COM	.file	"_div64.s"
270Sstevel@tonic-gate
280Sstevel@tonic-gate#include "SYS.h"
290Sstevel@tonic-gate
300Sstevel@tonic-gate/*
310Sstevel@tonic-gate * C support for 64-bit modulo and division.
320Sstevel@tonic-gate * Hand-customized compiler output - see comments for details.
330Sstevel@tonic-gate */
340Sstevel@tonic-gate
350Sstevel@tonic-gate/*
360Sstevel@tonic-gate * int32_t/int64_t division/manipulation
370Sstevel@tonic-gate *
380Sstevel@tonic-gate * Hand-customized compiler output: the non-GCC entry points depart from
390Sstevel@tonic-gate * the SYS V ABI by requiring their arguments to be popped, and in the
400Sstevel@tonic-gate * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the
410Sstevel@tonic-gate * compiler-generated use of %edx:%eax for the first argument of
420Sstevel@tonic-gate * internal entry points.
430Sstevel@tonic-gate *
440Sstevel@tonic-gate * Inlines for speed:
450Sstevel@tonic-gate * - counting the number of leading zeros in a word
460Sstevel@tonic-gate * - multiplying two 32-bit numbers giving a 64-bit result
470Sstevel@tonic-gate * - dividing a 64-bit number by a 32-bit number, giving both quotient
480Sstevel@tonic-gate *	and remainder
490Sstevel@tonic-gate * - subtracting two 64-bit results
500Sstevel@tonic-gate */
510Sstevel@tonic-gate/ #define	LO(X)		((uint32_t)(X) & 0xffffffff)
520Sstevel@tonic-gate/ #define	HI(X)		((uint32_t)((X) >> 32) & 0xffffffff)
530Sstevel@tonic-gate/ #define	HILO(H, L)	(((uint64_t)(H) << 32) + (L))
540Sstevel@tonic-gate/
550Sstevel@tonic-gate/ /* give index of highest bit */
560Sstevel@tonic-gate/ #define	HIBIT(a, r) \
570Sstevel@tonic-gate/     asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a))
580Sstevel@tonic-gate/
590Sstevel@tonic-gate/ /* multiply two uint32_ts resulting in a uint64_t */
600Sstevel@tonic-gate/ #define	A_MUL32(a, b, lo, hi) \
610Sstevel@tonic-gate/     asm("mull %2" \
620Sstevel@tonic-gate/ 	: "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a))
630Sstevel@tonic-gate/
640Sstevel@tonic-gate/ /* divide a uint64_t by a uint32_t */
650Sstevel@tonic-gate/ #define	A_DIV32(lo, hi, b, q, r) \
660Sstevel@tonic-gate/     asm("divl %2" \
670Sstevel@tonic-gate/ 	: "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \
680Sstevel@tonic-gate/ 	: "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi))
690Sstevel@tonic-gate/
700Sstevel@tonic-gate/ /* subtract two uint64_ts (with borrow) */
710Sstevel@tonic-gate/ #define	A_SUB2(bl, bh, al, ah) \
720Sstevel@tonic-gate/     asm("subl %4,%0\n\tsbbl %5,%1" \
730Sstevel@tonic-gate/ 	: "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \
740Sstevel@tonic-gate/ 	: "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \
750Sstevel@tonic-gate/ 	"g"((uint32_t)(bh)))
760Sstevel@tonic-gate/
770Sstevel@tonic-gate/ /*
780Sstevel@tonic-gate/  * Unsigned division with remainder.
790Sstevel@tonic-gate/  * Divide two uint64_ts, and calculate remainder.
800Sstevel@tonic-gate/  */
810Sstevel@tonic-gate/ uint64_t
820Sstevel@tonic-gate/ UDivRem(uint64_t x, uint64_t y, uint64_t * pmod)
830Sstevel@tonic-gate/ {
840Sstevel@tonic-gate/ 	/* simple cases: y is a single uint32_t */
850Sstevel@tonic-gate/ 	if (HI(y) == 0) {
860Sstevel@tonic-gate/ 		uint32_t	div_hi, div_rem;
870Sstevel@tonic-gate/ 		uint32_t 	q0, q1;
880Sstevel@tonic-gate/
890Sstevel@tonic-gate/ 		/* calculate q1 */
900Sstevel@tonic-gate/ 		if (HI(x) < LO(y)) {
910Sstevel@tonic-gate/ 			/* result is a single uint32_t, use one division */
920Sstevel@tonic-gate/ 			q1 = 0;
930Sstevel@tonic-gate/ 			div_hi = HI(x);
940Sstevel@tonic-gate/ 		} else {
950Sstevel@tonic-gate/ 			/* result is a double uint32_t, use two divisions */
960Sstevel@tonic-gate/ 			A_DIV32(HI(x), 0, LO(y), q1, div_hi);
970Sstevel@tonic-gate/ 		}
980Sstevel@tonic-gate/
990Sstevel@tonic-gate/ 		/* calculate q0 and remainder */
1000Sstevel@tonic-gate/ 		A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
1010Sstevel@tonic-gate/
1020Sstevel@tonic-gate/ 		/* return remainder */
1030Sstevel@tonic-gate/ 		*pmod = div_rem;
1040Sstevel@tonic-gate/
1050Sstevel@tonic-gate/ 		/* return result */
1060Sstevel@tonic-gate/ 		return (HILO(q1, q0));
1070Sstevel@tonic-gate/
1080Sstevel@tonic-gate/ 	} else if (HI(x) < HI(y)) {
1090Sstevel@tonic-gate/ 		/* HI(x) < HI(y) => x < y => result is 0 */
1100Sstevel@tonic-gate/
1110Sstevel@tonic-gate/ 		/* return remainder */
1120Sstevel@tonic-gate/ 		*pmod = x;
1130Sstevel@tonic-gate/
1140Sstevel@tonic-gate/ 		/* return result */
1150Sstevel@tonic-gate/ 		return (0);
1160Sstevel@tonic-gate/
1170Sstevel@tonic-gate/ 	} else {
1180Sstevel@tonic-gate/ 		/*
1190Sstevel@tonic-gate/ 		 * uint64_t by uint64_t division, resulting in a one-uint32_t
1200Sstevel@tonic-gate/ 		 * result
1210Sstevel@tonic-gate/ 		 */
1220Sstevel@tonic-gate/ 		uint32_t		y0, y1;
1230Sstevel@tonic-gate/ 		uint32_t		x1, x0;
1240Sstevel@tonic-gate/ 		uint32_t		q0;
1250Sstevel@tonic-gate/ 		uint32_t		normshift;
1260Sstevel@tonic-gate/
1270Sstevel@tonic-gate/ 		/* normalize by shifting x and y so MSB(y) == 1 */
1280Sstevel@tonic-gate/ 		HIBIT(HI(y), normshift);	/* index of highest 1 bit */
1290Sstevel@tonic-gate/ 		normshift = 31 - normshift;
1300Sstevel@tonic-gate/
1310Sstevel@tonic-gate/ 		if (normshift == 0) {
1320Sstevel@tonic-gate/ 			/* no shifting needed, and x < 2*y so q <= 1 */
1330Sstevel@tonic-gate/ 			y1 = HI(y);
1340Sstevel@tonic-gate/ 			y0 = LO(y);
1350Sstevel@tonic-gate/ 			x1 = HI(x);
1360Sstevel@tonic-gate/ 			x0 = LO(x);
1370Sstevel@tonic-gate/
1380Sstevel@tonic-gate/ 			/* if x >= y then q = 1 (note x1 >= y1) */
1390Sstevel@tonic-gate/ 			if (x1 > y1 || x0 >= y0) {
1400Sstevel@tonic-gate/ 				q0 = 1;
1410Sstevel@tonic-gate/ 				/* subtract y from x to get remainder */
1420Sstevel@tonic-gate/ 				A_SUB2(y0, y1, x0, x1);
1430Sstevel@tonic-gate/ 			} else {
1440Sstevel@tonic-gate/ 				q0 = 0;
1450Sstevel@tonic-gate/ 			}
1460Sstevel@tonic-gate/
1470Sstevel@tonic-gate/ 			/* return remainder */
1480Sstevel@tonic-gate/ 			*pmod = HILO(x1, x0);
1490Sstevel@tonic-gate/
1500Sstevel@tonic-gate/ 			/* return result */
1510Sstevel@tonic-gate/ 			return (q0);
1520Sstevel@tonic-gate/
1530Sstevel@tonic-gate/ 		} else {
1540Sstevel@tonic-gate/ 			/*
1550Sstevel@tonic-gate/ 			 * the last case: result is one uint32_t, but we need to
1560Sstevel@tonic-gate/ 			 * normalize
1570Sstevel@tonic-gate/ 			 */
1580Sstevel@tonic-gate/ 			uint64_t	dt;
1590Sstevel@tonic-gate/ 			uint32_t		t0, t1, x2;
1600Sstevel@tonic-gate/
1610Sstevel@tonic-gate/ 			/* normalize y */
1620Sstevel@tonic-gate/ 			dt = (y << normshift);
1630Sstevel@tonic-gate/ 			y1 = HI(dt);
1640Sstevel@tonic-gate/ 			y0 = LO(dt);
1650Sstevel@tonic-gate/
1660Sstevel@tonic-gate/ 			/* normalize x (we need 3 uint32_ts!!!) */
1670Sstevel@tonic-gate/ 			x2 = (HI(x) >> (32 - normshift));
1680Sstevel@tonic-gate/ 			dt = (x << normshift);
1690Sstevel@tonic-gate/ 			x1 = HI(dt);
1700Sstevel@tonic-gate/ 			x0 = LO(dt);
1710Sstevel@tonic-gate/
1720Sstevel@tonic-gate/ 			/* estimate q0, and reduce x to a two uint32_t value */
1730Sstevel@tonic-gate/ 			A_DIV32(x1, x2, y1, q0, x1);
1740Sstevel@tonic-gate/
1750Sstevel@tonic-gate/ 			/* adjust q0 down if too high */
1760Sstevel@tonic-gate/ 			/*
1770Sstevel@tonic-gate/ 			 * because of the limited range of x2 we can only be
1780Sstevel@tonic-gate/ 			 * one off
1790Sstevel@tonic-gate/ 			 */
1800Sstevel@tonic-gate/ 			A_MUL32(y0, q0, t0, t1);
1810Sstevel@tonic-gate/ 			if (t1 > x1 || (t1 == x1 && t0 > x0)) {
1820Sstevel@tonic-gate/ 				q0--;
1830Sstevel@tonic-gate/ 				A_SUB2(y0, y1, t0, t1);
1840Sstevel@tonic-gate/ 			}
1850Sstevel@tonic-gate/ 			/* return remainder */
1860Sstevel@tonic-gate/ 			/* subtract product from x to get remainder */
1870Sstevel@tonic-gate/ 			A_SUB2(t0, t1, x0, x1);
1880Sstevel@tonic-gate/ 			*pmod = (HILO(x1, x0) >> normshift);
1890Sstevel@tonic-gate/
1900Sstevel@tonic-gate/ 			/* return result */
1910Sstevel@tonic-gate/ 			return (q0);
1920Sstevel@tonic-gate/ 		}
1930Sstevel@tonic-gate/ 	}
1940Sstevel@tonic-gate/ }
1950Sstevel@tonic-gate	ENTRY(UDivRem)
1960Sstevel@tonic-gate	pushl	%ebp
1970Sstevel@tonic-gate	pushl	%edi
1980Sstevel@tonic-gate	pushl	%esi
1990Sstevel@tonic-gate	subl	$48, %esp
2000Sstevel@tonic-gate	movl	68(%esp), %edi	/ y,
2010Sstevel@tonic-gate	testl	%edi, %edi	/ tmp63
2020Sstevel@tonic-gate	movl	%eax, 40(%esp)	/ x, x
2030Sstevel@tonic-gate	movl	%edx, 44(%esp)	/ x, x
2040Sstevel@tonic-gate	movl	%edi, %esi	/, tmp62
2050Sstevel@tonic-gate	movl	%edi, %ecx	/ tmp62, tmp63
2060Sstevel@tonic-gate	jne	.LL2
2070Sstevel@tonic-gate	movl	%edx, %eax	/, tmp68
2080Sstevel@tonic-gate	cmpl	64(%esp), %eax	/ y, tmp68
2090Sstevel@tonic-gate	jae	.LL21
2100Sstevel@tonic-gate.LL4:
2110Sstevel@tonic-gate	movl	72(%esp), %ebp	/ pmod,
2120Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
2130Sstevel@tonic-gate	movl	40(%esp), %eax	/ x, q0
2140Sstevel@tonic-gate	movl	%ecx, %edi	/ <result>, <result>
2150Sstevel@tonic-gate	divl	64(%esp)	/ y
2160Sstevel@tonic-gate	movl	%edx, (%ebp)	/ div_rem,
2170Sstevel@tonic-gate	xorl	%edx, %edx	/ q0
2180Sstevel@tonic-gate	addl	%eax, %esi	/ q0, <result>
2190Sstevel@tonic-gate	movl	$0, 4(%ebp)
2200Sstevel@tonic-gate	adcl	%edx, %edi	/ q0, <result>
2210Sstevel@tonic-gate	addl	$48, %esp
2220Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
2230Sstevel@tonic-gate	popl	%esi
2240Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
2250Sstevel@tonic-gate	popl	%edi
2260Sstevel@tonic-gate	popl	%ebp
2270Sstevel@tonic-gate	ret
2280Sstevel@tonic-gate	.align	16
2290Sstevel@tonic-gate.LL2:
2300Sstevel@tonic-gate	movl	44(%esp), %eax	/ x,
2310Sstevel@tonic-gate	xorl	%edx, %edx
2320Sstevel@tonic-gate	cmpl	%esi, %eax	/ tmp62, tmp5
2330Sstevel@tonic-gate	movl	%eax, 32(%esp)	/ tmp5,
2340Sstevel@tonic-gate	movl	%edx, 36(%esp)
2350Sstevel@tonic-gate	jae	.LL6
2360Sstevel@tonic-gate	movl	72(%esp), %esi	/ pmod,
2370Sstevel@tonic-gate	movl	40(%esp), %ebp	/ x,
2380Sstevel@tonic-gate	movl	44(%esp), %ecx	/ x,
2390Sstevel@tonic-gate	movl	%ebp, (%esi)
2400Sstevel@tonic-gate	movl	%ecx, 4(%esi)
2410Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
2420Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
2430Sstevel@tonic-gate.LL22:
2440Sstevel@tonic-gate	addl	$48, %esp
2450Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
2460Sstevel@tonic-gate	popl	%esi
2470Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
2480Sstevel@tonic-gate	popl	%edi
2490Sstevel@tonic-gate	popl	%ebp
2500Sstevel@tonic-gate	ret
2510Sstevel@tonic-gate	.align	16
2520Sstevel@tonic-gate.LL21:
2530Sstevel@tonic-gate	movl	%edi, %edx	/ tmp63, div_hi
2540Sstevel@tonic-gate	divl	64(%esp)	/ y
2550Sstevel@tonic-gate	movl	%eax, %ecx	/, q1
2560Sstevel@tonic-gate	jmp	.LL4
2570Sstevel@tonic-gate	.align	16
2580Sstevel@tonic-gate.LL6:
2590Sstevel@tonic-gate	movl	$31, %edi	/, tmp87
2600Sstevel@tonic-gate	bsrl	%esi,%edx	/ tmp62, normshift
2610Sstevel@tonic-gate	subl	%edx, %edi	/ normshift, tmp87
2620Sstevel@tonic-gate	movl	%edi, 28(%esp)	/ tmp87,
2630Sstevel@tonic-gate	jne	.LL8
2640Sstevel@tonic-gate	movl	32(%esp), %edx	/, x1
2650Sstevel@tonic-gate	cmpl	%ecx, %edx	/ y1, x1
2660Sstevel@tonic-gate	movl	64(%esp), %edi	/ y, y0
2670Sstevel@tonic-gate	movl	40(%esp), %esi	/ x, x0
2680Sstevel@tonic-gate	ja	.LL10
2690Sstevel@tonic-gate	xorl	%ebp, %ebp	/ q0
2700Sstevel@tonic-gate	cmpl	%edi, %esi	/ y0, x0
2710Sstevel@tonic-gate	jb	.LL11
2720Sstevel@tonic-gate.LL10:
2730Sstevel@tonic-gate	movl	$1, %ebp	/, q0
2740Sstevel@tonic-gate	subl	%edi,%esi	/ y0, x0
2750Sstevel@tonic-gate	sbbl	%ecx,%edx	/ tmp63, x1
2760Sstevel@tonic-gate.LL11:
2770Sstevel@tonic-gate	movl	%edx, %ecx	/ x1, x1
2780Sstevel@tonic-gate	xorl	%edx, %edx	/ x1
2790Sstevel@tonic-gate	xorl	%edi, %edi	/ x0
2800Sstevel@tonic-gate	addl	%esi, %edx	/ x0, x1
2810Sstevel@tonic-gate	adcl	%edi, %ecx	/ x0, x1
2820Sstevel@tonic-gate	movl	72(%esp), %esi	/ pmod,
2830Sstevel@tonic-gate	movl	%edx, (%esi)	/ x1,
2840Sstevel@tonic-gate	movl	%ecx, 4(%esi)	/ x1,
2850Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
2860Sstevel@tonic-gate	movl	%ebp, %esi	/ q0, <result>
2870Sstevel@tonic-gate	jmp	.LL22
2880Sstevel@tonic-gate	.align	16
2890Sstevel@tonic-gate.LL8:
2900Sstevel@tonic-gate	movb	28(%esp), %cl
2910Sstevel@tonic-gate	movl	64(%esp), %esi	/ y, dt
2920Sstevel@tonic-gate	movl	68(%esp), %edi	/ y, dt
2930Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
2940Sstevel@tonic-gate	sall	%cl, %esi	/, dt
2950Sstevel@tonic-gate	andl	$32, %ecx
2960Sstevel@tonic-gate	jne	.LL23
2970Sstevel@tonic-gate.LL17:
2980Sstevel@tonic-gate	movl	$32, %ecx	/, tmp102
2990Sstevel@tonic-gate	subl	28(%esp), %ecx	/, tmp102
3000Sstevel@tonic-gate	movl	%esi, %ebp	/ dt, y0
3010Sstevel@tonic-gate	movl	32(%esp), %esi
3020Sstevel@tonic-gate	shrl	%cl, %esi	/ tmp102,
3030Sstevel@tonic-gate	movl	%edi, 24(%esp)	/ tmp99,
3040Sstevel@tonic-gate	movb	28(%esp), %cl
3050Sstevel@tonic-gate	movl	%esi, 12(%esp)	/, x2
3060Sstevel@tonic-gate	movl	44(%esp), %edi	/ x, dt
3070Sstevel@tonic-gate	movl	40(%esp), %esi	/ x, dt
3080Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
3090Sstevel@tonic-gate	sall	%cl, %esi	/, dt
3100Sstevel@tonic-gate	andl	$32, %ecx
3110Sstevel@tonic-gate	je	.LL18
3120Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
3130Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
3140Sstevel@tonic-gate.LL18:
3150Sstevel@tonic-gate	movl	%edi, %ecx	/ dt,
3160Sstevel@tonic-gate	movl	%edi, %eax	/ tmp2,
3170Sstevel@tonic-gate	movl	%ecx, (%esp)
3180Sstevel@tonic-gate	movl	12(%esp), %edx	/ x2,
3190Sstevel@tonic-gate	divl	24(%esp)
3200Sstevel@tonic-gate	movl	%edx, %ecx	/, x1
3210Sstevel@tonic-gate	xorl	%edi, %edi
3220Sstevel@tonic-gate	movl	%eax, 20(%esp)
3230Sstevel@tonic-gate	movl	%ebp, %eax	/ y0, t0
3240Sstevel@tonic-gate	mull	20(%esp)
3250Sstevel@tonic-gate	cmpl	%ecx, %edx	/ x1, t1
3260Sstevel@tonic-gate	movl	%edi, 4(%esp)
3270Sstevel@tonic-gate	ja	.LL14
3280Sstevel@tonic-gate	je	.LL24
3290Sstevel@tonic-gate.LL15:
3300Sstevel@tonic-gate	movl	%ecx, %edi	/ x1,
3310Sstevel@tonic-gate	subl	%eax,%esi	/ t0, x0
3320Sstevel@tonic-gate	sbbl	%edx,%edi	/ t1,
3330Sstevel@tonic-gate	movl	%edi, %eax	/, x1
3340Sstevel@tonic-gate	movl	%eax, %edx	/ x1, x1
3350Sstevel@tonic-gate	xorl	%eax, %eax	/ x1
3360Sstevel@tonic-gate	xorl	%ebp, %ebp	/ x0
3370Sstevel@tonic-gate	addl	%esi, %eax	/ x0, x1
3380Sstevel@tonic-gate	adcl	%ebp, %edx	/ x0, x1
3390Sstevel@tonic-gate	movb	28(%esp), %cl
3400Sstevel@tonic-gate	shrdl	%edx, %eax	/, x1, x1
3410Sstevel@tonic-gate	shrl	%cl, %edx	/, x1
3420Sstevel@tonic-gate	andl	$32, %ecx
3430Sstevel@tonic-gate	je	.LL16
3440Sstevel@tonic-gate	movl	%edx, %eax	/ x1, x1
3450Sstevel@tonic-gate	xorl	%edx, %edx	/ x1
3460Sstevel@tonic-gate.LL16:
3470Sstevel@tonic-gate	movl	72(%esp), %ecx	/ pmod,
3480Sstevel@tonic-gate	movl	20(%esp), %esi	/, <result>
3490Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
3500Sstevel@tonic-gate	movl	%eax, (%ecx)	/ x1,
3510Sstevel@tonic-gate	movl	%edx, 4(%ecx)	/ x1,
3520Sstevel@tonic-gate	jmp	.LL22
3530Sstevel@tonic-gate	.align	16
3540Sstevel@tonic-gate.LL24:
3550Sstevel@tonic-gate	cmpl	%esi, %eax	/ x0, t0
3560Sstevel@tonic-gate	jbe	.LL15
3570Sstevel@tonic-gate.LL14:
3580Sstevel@tonic-gate	decl	20(%esp)
3590Sstevel@tonic-gate	subl	%ebp,%eax	/ y0, t0
3600Sstevel@tonic-gate	sbbl	24(%esp),%edx	/, t1
3610Sstevel@tonic-gate	jmp	.LL15
3620Sstevel@tonic-gate.LL23:
3630Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
3640Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
3650Sstevel@tonic-gate	jmp	.LL17
3660Sstevel@tonic-gate	SET_SIZE(UDivRem)
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate/*
3690Sstevel@tonic-gate * Unsigned division without remainder.
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate/ uint64_t
3720Sstevel@tonic-gate/ UDiv(uint64_t x, uint64_t y)
3730Sstevel@tonic-gate/ {
3740Sstevel@tonic-gate/ 	if (HI(y) == 0) {
3750Sstevel@tonic-gate/ 		/* simple cases: y is a single uint32_t */
3760Sstevel@tonic-gate/ 		uint32_t	div_hi, div_rem;
3770Sstevel@tonic-gate/ 		uint32_t	q0, q1;
3780Sstevel@tonic-gate/
3790Sstevel@tonic-gate/ 		/* calculate q1 */
3800Sstevel@tonic-gate/ 		if (HI(x) < LO(y)) {
3810Sstevel@tonic-gate/ 			/* result is a single uint32_t, use one division */
3820Sstevel@tonic-gate/ 			q1 = 0;
3830Sstevel@tonic-gate/ 			div_hi = HI(x);
3840Sstevel@tonic-gate/ 		} else {
3850Sstevel@tonic-gate/ 			/* result is a double uint32_t, use two divisions */
3860Sstevel@tonic-gate/ 			A_DIV32(HI(x), 0, LO(y), q1, div_hi);
3870Sstevel@tonic-gate/ 		}
3880Sstevel@tonic-gate/
3890Sstevel@tonic-gate/ 		/* calculate q0 and remainder */
3900Sstevel@tonic-gate/ 		A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
3910Sstevel@tonic-gate/
3920Sstevel@tonic-gate/ 		/* return result */
3930Sstevel@tonic-gate/ 		return (HILO(q1, q0));
3940Sstevel@tonic-gate/
3950Sstevel@tonic-gate/ 	} else if (HI(x) < HI(y)) {
3960Sstevel@tonic-gate/ 		/* HI(x) < HI(y) => x < y => result is 0 */
3970Sstevel@tonic-gate/
3980Sstevel@tonic-gate/ 		/* return result */
3990Sstevel@tonic-gate/ 		return (0);
4000Sstevel@tonic-gate/
4010Sstevel@tonic-gate/ 	} else {
4020Sstevel@tonic-gate/ 		/*
4030Sstevel@tonic-gate/ 		 * uint64_t by uint64_t division, resulting in a one-uint32_t
4040Sstevel@tonic-gate/ 		 * result
4050Sstevel@tonic-gate/ 		 */
4060Sstevel@tonic-gate/ 		uint32_t		y0, y1;
4070Sstevel@tonic-gate/ 		uint32_t		x1, x0;
4080Sstevel@tonic-gate/ 		uint32_t		q0;
4090Sstevel@tonic-gate/ 		unsigned		normshift;
4100Sstevel@tonic-gate/
4110Sstevel@tonic-gate/ 		/* normalize by shifting x and y so MSB(y) == 1 */
4120Sstevel@tonic-gate/ 		HIBIT(HI(y), normshift);	/* index of highest 1 bit */
4130Sstevel@tonic-gate/ 		normshift = 31 - normshift;
4140Sstevel@tonic-gate/
4150Sstevel@tonic-gate/ 		if (normshift == 0) {
4160Sstevel@tonic-gate/ 			/* no shifting needed, and x < 2*y so q <= 1 */
4170Sstevel@tonic-gate/ 			y1 = HI(y);
4180Sstevel@tonic-gate/ 			y0 = LO(y);
4190Sstevel@tonic-gate/ 			x1 = HI(x);
4200Sstevel@tonic-gate/ 			x0 = LO(x);
4210Sstevel@tonic-gate/
4220Sstevel@tonic-gate/ 			/* if x >= y then q = 1 (note x1 >= y1) */
4230Sstevel@tonic-gate/ 			if (x1 > y1 || x0 >= y0) {
4240Sstevel@tonic-gate/ 				q0 = 1;
4250Sstevel@tonic-gate/ 				/* subtract y from x to get remainder */
4260Sstevel@tonic-gate/ 				/* A_SUB2(y0, y1, x0, x1); */
4270Sstevel@tonic-gate/ 			} else {
4280Sstevel@tonic-gate/ 				q0 = 0;
4290Sstevel@tonic-gate/ 			}
4300Sstevel@tonic-gate/
4310Sstevel@tonic-gate/ 			/* return result */
4320Sstevel@tonic-gate/ 			return (q0);
4330Sstevel@tonic-gate/
4340Sstevel@tonic-gate/ 		} else {
4350Sstevel@tonic-gate/ 			/*
4360Sstevel@tonic-gate/ 			 * the last case: result is one uint32_t, but we need to
4370Sstevel@tonic-gate/ 			 * normalize
4380Sstevel@tonic-gate/ 			 */
4390Sstevel@tonic-gate/ 			uint64_t	dt;
4400Sstevel@tonic-gate/ 			uint32_t		t0, t1, x2;
4410Sstevel@tonic-gate/
4420Sstevel@tonic-gate/ 			/* normalize y */
4430Sstevel@tonic-gate/ 			dt = (y << normshift);
4440Sstevel@tonic-gate/ 			y1 = HI(dt);
4450Sstevel@tonic-gate/ 			y0 = LO(dt);
4460Sstevel@tonic-gate/
4470Sstevel@tonic-gate/ 			/* normalize x (we need 3 uint32_ts!!!) */
4480Sstevel@tonic-gate/ 			x2 = (HI(x) >> (32 - normshift));
4490Sstevel@tonic-gate/ 			dt = (x << normshift);
4500Sstevel@tonic-gate/ 			x1 = HI(dt);
4510Sstevel@tonic-gate/ 			x0 = LO(dt);
4520Sstevel@tonic-gate/
4530Sstevel@tonic-gate/ 			/* estimate q0, and reduce x to a two uint32_t value */
4540Sstevel@tonic-gate/ 			A_DIV32(x1, x2, y1, q0, x1);
4550Sstevel@tonic-gate/
4560Sstevel@tonic-gate/ 			/* adjust q0 down if too high */
4570Sstevel@tonic-gate/ 			/*
4580Sstevel@tonic-gate/ 			 * because of the limited range of x2 we can only be
4590Sstevel@tonic-gate/ 			 * one off
4600Sstevel@tonic-gate/ 			 */
4610Sstevel@tonic-gate/ 			A_MUL32(y0, q0, t0, t1);
4620Sstevel@tonic-gate/ 			if (t1 > x1 || (t1 == x1 && t0 > x0)) {
4630Sstevel@tonic-gate/ 				q0--;
4640Sstevel@tonic-gate/ 			}
4650Sstevel@tonic-gate/ 			/* return result */
4660Sstevel@tonic-gate/ 			return (q0);
4670Sstevel@tonic-gate/ 		}
4680Sstevel@tonic-gate/ 	}
4690Sstevel@tonic-gate/ }
4700Sstevel@tonic-gate	ENTRY(UDiv)
4710Sstevel@tonic-gate	pushl	%ebp
4720Sstevel@tonic-gate	pushl	%edi
4730Sstevel@tonic-gate	pushl	%esi
4740Sstevel@tonic-gate	subl	$40, %esp
4750Sstevel@tonic-gate	movl	%edx, 36(%esp)	/ x, x
4760Sstevel@tonic-gate	movl	60(%esp), %edx	/ y,
4770Sstevel@tonic-gate	testl	%edx, %edx	/ tmp62
4780Sstevel@tonic-gate	movl	%eax, 32(%esp)	/ x, x
4790Sstevel@tonic-gate	movl	%edx, %ecx	/ tmp61, tmp62
4800Sstevel@tonic-gate	movl	%edx, %eax	/, tmp61
4810Sstevel@tonic-gate	jne	.LL26
4820Sstevel@tonic-gate	movl	36(%esp), %esi	/ x,
4830Sstevel@tonic-gate	cmpl	56(%esp), %esi	/ y, tmp67
4840Sstevel@tonic-gate	movl	%esi, %eax	/, tmp67
4850Sstevel@tonic-gate	movl	%esi, %edx	/ tmp67, div_hi
4860Sstevel@tonic-gate	jb	.LL28
4870Sstevel@tonic-gate	movl	%ecx, %edx	/ tmp62, div_hi
4880Sstevel@tonic-gate	divl	56(%esp)	/ y
4890Sstevel@tonic-gate	movl	%eax, %ecx	/, q1
4900Sstevel@tonic-gate.LL28:
4910Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
4920Sstevel@tonic-gate	movl	%ecx, %edi	/ <result>, <result>
4930Sstevel@tonic-gate	movl	32(%esp), %eax	/ x, q0
4940Sstevel@tonic-gate	xorl	%ecx, %ecx	/ q0
4950Sstevel@tonic-gate	divl	56(%esp)	/ y
4960Sstevel@tonic-gate	addl	%eax, %esi	/ q0, <result>
4970Sstevel@tonic-gate	adcl	%ecx, %edi	/ q0, <result>
4980Sstevel@tonic-gate.LL25:
4990Sstevel@tonic-gate	addl	$40, %esp
5000Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
5010Sstevel@tonic-gate	popl	%esi
5020Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
5030Sstevel@tonic-gate	popl	%edi
5040Sstevel@tonic-gate	popl	%ebp
5050Sstevel@tonic-gate	ret
5060Sstevel@tonic-gate	.align	16
5070Sstevel@tonic-gate.LL26:
5080Sstevel@tonic-gate	movl	36(%esp), %esi	/ x,
5090Sstevel@tonic-gate	xorl	%edi, %edi
5100Sstevel@tonic-gate	movl	%esi, 24(%esp)	/ tmp1,
5110Sstevel@tonic-gate	movl	%edi, 28(%esp)
5120Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
5130Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
5140Sstevel@tonic-gate	cmpl	%eax, 24(%esp)	/ tmp61,
5150Sstevel@tonic-gate	jb	.LL25
5160Sstevel@tonic-gate	bsrl	%eax,%ebp	/ tmp61, normshift
5170Sstevel@tonic-gate	movl	$31, %eax	/, tmp85
5180Sstevel@tonic-gate	subl	%ebp, %eax	/ normshift, normshift
5190Sstevel@tonic-gate	jne	.LL32
5200Sstevel@tonic-gate	movl	24(%esp), %eax	/, x1
5210Sstevel@tonic-gate	cmpl	%ecx, %eax	/ tmp62, x1
5220Sstevel@tonic-gate	movl	56(%esp), %esi	/ y, y0
5230Sstevel@tonic-gate	movl	32(%esp), %edx	/ x, x0
5240Sstevel@tonic-gate	ja	.LL34
5250Sstevel@tonic-gate	xorl	%eax, %eax	/ q0
5260Sstevel@tonic-gate	cmpl	%esi, %edx	/ y0, x0
5270Sstevel@tonic-gate	jb	.LL35
5280Sstevel@tonic-gate.LL34:
5290Sstevel@tonic-gate	movl	$1, %eax	/, q0
5300Sstevel@tonic-gate.LL35:
5310Sstevel@tonic-gate	movl	%eax, %esi	/ q0, <result>
5320Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
5330Sstevel@tonic-gate.LL45:
5340Sstevel@tonic-gate	addl	$40, %esp
5350Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
5360Sstevel@tonic-gate	popl	%esi
5370Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
5380Sstevel@tonic-gate	popl	%edi
5390Sstevel@tonic-gate	popl	%ebp
5400Sstevel@tonic-gate	ret
5410Sstevel@tonic-gate	.align	16
5420Sstevel@tonic-gate.LL32:
5430Sstevel@tonic-gate	movb	%al, %cl
5440Sstevel@tonic-gate	movl	56(%esp), %esi	/ y,
5450Sstevel@tonic-gate	movl	60(%esp), %edi	/ y,
5460Sstevel@tonic-gate	shldl	%esi, %edi
5470Sstevel@tonic-gate	sall	%cl, %esi
5480Sstevel@tonic-gate	andl	$32, %ecx
5490Sstevel@tonic-gate	jne	.LL43
5500Sstevel@tonic-gate.LL40:
5510Sstevel@tonic-gate	movl	$32, %ecx	/, tmp96
5520Sstevel@tonic-gate	subl	%eax, %ecx	/ normshift, tmp96
5530Sstevel@tonic-gate	movl	%edi, %edx
5540Sstevel@tonic-gate	movl	%edi, 20(%esp)	/, dt
5550Sstevel@tonic-gate	movl	24(%esp), %ebp	/, x2
5560Sstevel@tonic-gate	xorl	%edi, %edi
5570Sstevel@tonic-gate	shrl	%cl, %ebp	/ tmp96, x2
5580Sstevel@tonic-gate	movl	%esi, 16(%esp)	/, dt
5590Sstevel@tonic-gate	movb	%al, %cl
5600Sstevel@tonic-gate	movl	32(%esp), %esi	/ x, dt
5610Sstevel@tonic-gate	movl	%edi, 12(%esp)
5620Sstevel@tonic-gate	movl	36(%esp), %edi	/ x, dt
5630Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
5640Sstevel@tonic-gate	sall	%cl, %esi	/, dt
5650Sstevel@tonic-gate	andl	$32, %ecx
5660Sstevel@tonic-gate	movl	%edx, 8(%esp)
5670Sstevel@tonic-gate	je	.LL41
5680Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
5690Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
5700Sstevel@tonic-gate.LL41:
5710Sstevel@tonic-gate	xorl	%ecx, %ecx
5720Sstevel@tonic-gate	movl	%edi, %eax	/ tmp1,
5730Sstevel@tonic-gate	movl	%ebp, %edx	/ x2,
5740Sstevel@tonic-gate	divl	8(%esp)
5750Sstevel@tonic-gate	movl	%edx, %ebp	/, x1
5760Sstevel@tonic-gate	movl	%ecx, 4(%esp)
5770Sstevel@tonic-gate	movl	%eax, %ecx	/, q0
5780Sstevel@tonic-gate	movl	16(%esp), %eax	/ dt,
5790Sstevel@tonic-gate	mull	%ecx	/ q0
5800Sstevel@tonic-gate	cmpl	%ebp, %edx	/ x1, t1
5810Sstevel@tonic-gate	movl	%edi, (%esp)
5820Sstevel@tonic-gate	movl	%esi, %edi	/ dt, x0
5830Sstevel@tonic-gate	ja	.LL38
5840Sstevel@tonic-gate	je	.LL44
5850Sstevel@tonic-gate.LL39:
5860Sstevel@tonic-gate	movl	%ecx, %esi	/ q0, <result>
5870Sstevel@tonic-gate.LL46:
5880Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
5890Sstevel@tonic-gate	jmp	.LL45
5900Sstevel@tonic-gate.LL44:
5910Sstevel@tonic-gate	cmpl	%edi, %eax	/ x0, t0
5920Sstevel@tonic-gate	jbe	.LL39
5930Sstevel@tonic-gate.LL38:
5940Sstevel@tonic-gate	decl	%ecx		/ q0
5950Sstevel@tonic-gate	movl	%ecx, %esi	/ q0, <result>
5960Sstevel@tonic-gate	jmp	.LL46
5970Sstevel@tonic-gate.LL43:
5980Sstevel@tonic-gate	movl	%esi, %edi
5990Sstevel@tonic-gate	xorl	%esi, %esi
6000Sstevel@tonic-gate	jmp	.LL40
6010Sstevel@tonic-gate	SET_SIZE(UDiv)
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate/*
6040Sstevel@tonic-gate * __udiv64
6050Sstevel@tonic-gate *
6060Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the
6070Sstevel@tonic-gate * quotient in %edx:%eax.  __udiv64 pops the arguments on return,
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate	ENTRY(__udiv64)
6100Sstevel@tonic-gate	movl	4(%esp), %eax	/ x, x
6110Sstevel@tonic-gate	movl	8(%esp), %edx	/ x, x
6120Sstevel@tonic-gate	pushl	16(%esp)	/ y
6130Sstevel@tonic-gate	pushl	16(%esp)
6140Sstevel@tonic-gate	call	UDiv
6150Sstevel@tonic-gate	addl	$8, %esp
6160Sstevel@tonic-gate	ret     $16
6170Sstevel@tonic-gate	SET_SIZE(__udiv64)
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate/*
6200Sstevel@tonic-gate * __urem64
6210Sstevel@tonic-gate *
6220Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the
6230Sstevel@tonic-gate * remainder in %edx:%eax.  __urem64 pops the arguments on return
6240Sstevel@tonic-gate */
6250Sstevel@tonic-gate	ENTRY(__urem64)
6260Sstevel@tonic-gate	subl	$12, %esp
6270Sstevel@tonic-gate	movl	%esp, %ecx	/, tmp65
6280Sstevel@tonic-gate	movl	16(%esp), %eax	/ x, x
6290Sstevel@tonic-gate	movl	20(%esp), %edx	/ x, x
6300Sstevel@tonic-gate	pushl	%ecx		/ tmp65
6310Sstevel@tonic-gate	pushl	32(%esp)	/ y
6320Sstevel@tonic-gate	pushl	32(%esp)
6330Sstevel@tonic-gate	call	UDivRem
6340Sstevel@tonic-gate	movl	12(%esp), %eax	/ rem, rem
6350Sstevel@tonic-gate	movl	16(%esp), %edx	/ rem, rem
6360Sstevel@tonic-gate	addl	$24, %esp
6370Sstevel@tonic-gate	ret	$16
6380Sstevel@tonic-gate	SET_SIZE(__urem64)
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate/*
6410Sstevel@tonic-gate * __div64
6420Sstevel@tonic-gate *
6430Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the
6440Sstevel@tonic-gate * quotient in %edx:%eax.  __div64 pops the arguments on return.
6450Sstevel@tonic-gate */
6460Sstevel@tonic-gate/ int64_t
6470Sstevel@tonic-gate/ __div64(int64_t x, int64_t y)
6480Sstevel@tonic-gate/ {
6490Sstevel@tonic-gate/ 	int		negative;
6500Sstevel@tonic-gate/ 	uint64_t	xt, yt, r;
6510Sstevel@tonic-gate/
6520Sstevel@tonic-gate/ 	if (x < 0) {
6530Sstevel@tonic-gate/ 		xt = -(uint64_t) x;
6540Sstevel@tonic-gate/ 		negative = 1;
6550Sstevel@tonic-gate/ 	} else {
6560Sstevel@tonic-gate/ 		xt = x;
6570Sstevel@tonic-gate/ 		negative = 0;
6580Sstevel@tonic-gate/ 	}
6590Sstevel@tonic-gate/ 	if (y < 0) {
6600Sstevel@tonic-gate/ 		yt = -(uint64_t) y;
6610Sstevel@tonic-gate/ 		negative ^= 1;
6620Sstevel@tonic-gate/ 	} else {
6630Sstevel@tonic-gate/ 		yt = y;
6640Sstevel@tonic-gate/ 	}
6650Sstevel@tonic-gate/ 	r = UDiv(xt, yt);
6660Sstevel@tonic-gate/ 	return (negative ? (int64_t) - r : r);
6670Sstevel@tonic-gate/ }
6680Sstevel@tonic-gate	ENTRY(__div64)
6690Sstevel@tonic-gate	pushl	%ebp
6700Sstevel@tonic-gate	pushl	%edi
6710Sstevel@tonic-gate	pushl	%esi
6720Sstevel@tonic-gate	subl	$8, %esp
6730Sstevel@tonic-gate	movl	28(%esp), %edx	/ x, x
6740Sstevel@tonic-gate	testl	%edx, %edx	/ x
6750Sstevel@tonic-gate	movl	24(%esp), %eax	/ x, x
6760Sstevel@tonic-gate	movl	32(%esp), %esi	/ y, y
6770Sstevel@tonic-gate	movl	36(%esp), %edi	/ y, y
6780Sstevel@tonic-gate	js	.LL84
6790Sstevel@tonic-gate	xorl	%ebp, %ebp	/ negative
6800Sstevel@tonic-gate	testl	%edi, %edi	/ y
6810Sstevel@tonic-gate	movl	%eax, (%esp)	/ x, xt
6820Sstevel@tonic-gate	movl	%edx, 4(%esp)	/ x, xt
6830Sstevel@tonic-gate	movl	%esi, %eax	/ y, yt
6840Sstevel@tonic-gate	movl	%edi, %edx	/ y, yt
6850Sstevel@tonic-gate	js	.LL85
6860Sstevel@tonic-gate.LL82:
6870Sstevel@tonic-gate	pushl	%edx		/ yt
6880Sstevel@tonic-gate	pushl	%eax		/ yt
6890Sstevel@tonic-gate	movl	8(%esp), %eax	/ xt, xt
6900Sstevel@tonic-gate	movl	12(%esp), %edx	/ xt, xt
6910Sstevel@tonic-gate	call	UDiv
6920Sstevel@tonic-gate	popl	%ecx
6930Sstevel@tonic-gate	testl	%ebp, %ebp	/ negative
6940Sstevel@tonic-gate	popl	%esi
6950Sstevel@tonic-gate	je	.LL83
6960Sstevel@tonic-gate	negl	%eax		/ r
6970Sstevel@tonic-gate	adcl	$0, %edx	/, r
6980Sstevel@tonic-gate	negl	%edx		/ r
6990Sstevel@tonic-gate.LL83:
7000Sstevel@tonic-gate	addl	$8, %esp
7010Sstevel@tonic-gate	popl	%esi
7020Sstevel@tonic-gate	popl	%edi
7030Sstevel@tonic-gate	popl	%ebp
7040Sstevel@tonic-gate	ret	$16
7050Sstevel@tonic-gate	.align	16
7060Sstevel@tonic-gate.LL84:
7070Sstevel@tonic-gate	negl	%eax		/ x
7080Sstevel@tonic-gate	adcl	$0, %edx	/, x
7090Sstevel@tonic-gate	negl	%edx		/ x
7100Sstevel@tonic-gate	testl	%edi, %edi	/ y
7110Sstevel@tonic-gate	movl	%eax, (%esp)	/ x, xt
7120Sstevel@tonic-gate	movl	%edx, 4(%esp)	/ x, xt
7130Sstevel@tonic-gate	movl	$1, %ebp	/, negative
7140Sstevel@tonic-gate	movl	%esi, %eax	/ y, yt
7150Sstevel@tonic-gate	movl	%edi, %edx	/ y, yt
7160Sstevel@tonic-gate	jns	.LL82
7170Sstevel@tonic-gate	.align	16
7180Sstevel@tonic-gate.LL85:
7190Sstevel@tonic-gate	negl	%eax		/ yt
7200Sstevel@tonic-gate	adcl	$0, %edx	/, yt
7210Sstevel@tonic-gate	negl	%edx		/ yt
7220Sstevel@tonic-gate	xorl	$1, %ebp	/, negative
7230Sstevel@tonic-gate	jmp	.LL82
7240Sstevel@tonic-gate	SET_SIZE(__div64)
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate/*
7270Sstevel@tonic-gate * __rem64
7280Sstevel@tonic-gate *
7290Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the
7300Sstevel@tonic-gate * remainder in %edx:%eax.  __rem64 pops the arguments on return.
7310Sstevel@tonic-gate */
7320Sstevel@tonic-gate/ int64_t
7330Sstevel@tonic-gate/ __rem64(int64_t x, int64_t y)
7340Sstevel@tonic-gate/ {
7350Sstevel@tonic-gate/ 	uint64_t	xt, yt, rem;
7360Sstevel@tonic-gate/
7370Sstevel@tonic-gate/ 	if (x < 0) {
7380Sstevel@tonic-gate/ 		xt = -(uint64_t) x;
7390Sstevel@tonic-gate/ 	} else {
7400Sstevel@tonic-gate/ 		xt = x;
7410Sstevel@tonic-gate/ 	}
7420Sstevel@tonic-gate/ 	if (y < 0) {
7430Sstevel@tonic-gate/ 		yt = -(uint64_t) y;
7440Sstevel@tonic-gate/ 	} else {
7450Sstevel@tonic-gate/ 		yt = y;
7460Sstevel@tonic-gate/ 	}
7470Sstevel@tonic-gate/ 	(void) UDivRem(xt, yt, &rem);
7480Sstevel@tonic-gate/ 	return (x < 0 ? (int64_t) - rem : rem);
7490Sstevel@tonic-gate/ }
7500Sstevel@tonic-gate	ENTRY(__rem64)
7510Sstevel@tonic-gate	pushl	%edi
7520Sstevel@tonic-gate	pushl	%esi
7530Sstevel@tonic-gate	subl	$20, %esp
7540Sstevel@tonic-gate	movl	36(%esp), %ecx	/ x,
7550Sstevel@tonic-gate	movl	32(%esp), %esi	/ x,
7560Sstevel@tonic-gate	movl	36(%esp), %edi	/ x,
7570Sstevel@tonic-gate	testl	%ecx, %ecx
7580Sstevel@tonic-gate	movl	40(%esp), %eax	/ y, y
7590Sstevel@tonic-gate	movl	44(%esp), %edx	/ y, y
7600Sstevel@tonic-gate	movl	%esi, (%esp)	/, xt
7610Sstevel@tonic-gate	movl	%edi, 4(%esp)	/, xt
7620Sstevel@tonic-gate	js	.LL92
7630Sstevel@tonic-gate	testl	%edx, %edx	/ y
7640Sstevel@tonic-gate	movl	%eax, %esi	/ y, yt
7650Sstevel@tonic-gate	movl	%edx, %edi	/ y, yt
7660Sstevel@tonic-gate	js	.LL93
7670Sstevel@tonic-gate.LL90:
7680Sstevel@tonic-gate	leal	8(%esp), %eax	/, tmp66
7690Sstevel@tonic-gate	pushl	%eax		/ tmp66
7700Sstevel@tonic-gate	pushl	%edi		/ yt
7710Sstevel@tonic-gate	pushl	%esi		/ yt
7720Sstevel@tonic-gate	movl	12(%esp), %eax	/ xt, xt
7730Sstevel@tonic-gate	movl	16(%esp), %edx	/ xt, xt
7740Sstevel@tonic-gate	call	UDivRem
7750Sstevel@tonic-gate	addl	$12, %esp
7760Sstevel@tonic-gate	movl	36(%esp), %edi	/ x,
7770Sstevel@tonic-gate	testl	%edi, %edi
7780Sstevel@tonic-gate	movl	8(%esp), %eax	/ rem, rem
7790Sstevel@tonic-gate	movl	12(%esp), %edx	/ rem, rem
7800Sstevel@tonic-gate	js	.LL94
7810Sstevel@tonic-gate	addl	$20, %esp
7820Sstevel@tonic-gate	popl	%esi
7830Sstevel@tonic-gate	popl	%edi
7840Sstevel@tonic-gate	ret	$16
7850Sstevel@tonic-gate	.align	16
7860Sstevel@tonic-gate.LL92:
7870Sstevel@tonic-gate	negl	%esi
7880Sstevel@tonic-gate	adcl	$0, %edi
7890Sstevel@tonic-gate	negl	%edi
7900Sstevel@tonic-gate	testl	%edx, %edx	/ y
7910Sstevel@tonic-gate	movl	%esi, (%esp)	/, xt
7920Sstevel@tonic-gate	movl	%edi, 4(%esp)	/, xt
7930Sstevel@tonic-gate	movl	%eax, %esi	/ y, yt
7940Sstevel@tonic-gate	movl	%edx, %edi	/ y, yt
7950Sstevel@tonic-gate	jns	.LL90
7960Sstevel@tonic-gate	.align	16
7970Sstevel@tonic-gate.LL93:
7980Sstevel@tonic-gate	negl	%esi		/ yt
7990Sstevel@tonic-gate	adcl	$0, %edi	/, yt
8000Sstevel@tonic-gate	negl	%edi		/ yt
8010Sstevel@tonic-gate	jmp	.LL90
8020Sstevel@tonic-gate	.align	16
8030Sstevel@tonic-gate.LL94:
8040Sstevel@tonic-gate	negl	%eax		/ rem
8050Sstevel@tonic-gate	adcl	$0, %edx	/, rem
8060Sstevel@tonic-gate	addl	$20, %esp
8070Sstevel@tonic-gate	popl	%esi
8080Sstevel@tonic-gate	negl	%edx		/ rem
8090Sstevel@tonic-gate	popl	%edi
8100Sstevel@tonic-gate	ret	$16
8110Sstevel@tonic-gate	SET_SIZE(__rem64)
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate/*
8140Sstevel@tonic-gate * __udivrem64
8150Sstevel@tonic-gate *
8160Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the
8170Sstevel@tonic-gate * quotient in %edx:%eax, and the remainder in %ecx:%esi.  __udivrem64
8180Sstevel@tonic-gate * pops the arguments on return.
8190Sstevel@tonic-gate */
8200Sstevel@tonic-gate	ENTRY(__udivrem64)
8210Sstevel@tonic-gate	subl	$12, %esp
8220Sstevel@tonic-gate	movl	%esp, %ecx	/, tmp64
8230Sstevel@tonic-gate	movl	16(%esp), %eax	/ x, x
8240Sstevel@tonic-gate	movl	20(%esp), %edx	/ x, x
8250Sstevel@tonic-gate	pushl	%ecx		/ tmp64
8260Sstevel@tonic-gate	pushl	32(%esp)	/ y
8270Sstevel@tonic-gate	pushl	32(%esp)
8280Sstevel@tonic-gate	call	UDivRem
8290Sstevel@tonic-gate	movl	16(%esp), %ecx	/ rem, tmp63
8300Sstevel@tonic-gate	movl	12(%esp), %esi	/ rem
8310Sstevel@tonic-gate	addl	$24, %esp
8320Sstevel@tonic-gate	ret	$16
8330Sstevel@tonic-gate	SET_SIZE(__udivrem64)
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate/*
8360Sstevel@tonic-gate * Signed division with remainder.
8370Sstevel@tonic-gate */
8380Sstevel@tonic-gate/ int64_t
8390Sstevel@tonic-gate/ SDivRem(int64_t x, int64_t y, int64_t * pmod)
8400Sstevel@tonic-gate/ {
8410Sstevel@tonic-gate/ 	int		negative;
8420Sstevel@tonic-gate/ 	uint64_t	xt, yt, r, rem;
8430Sstevel@tonic-gate/
8440Sstevel@tonic-gate/ 	if (x < 0) {
8450Sstevel@tonic-gate/ 		xt = -(uint64_t) x;
8460Sstevel@tonic-gate/ 		negative = 1;
8470Sstevel@tonic-gate/ 	} else {
8480Sstevel@tonic-gate/ 		xt = x;
8490Sstevel@tonic-gate/ 		negative = 0;
8500Sstevel@tonic-gate/ 	}
8510Sstevel@tonic-gate/ 	if (y < 0) {
8520Sstevel@tonic-gate/ 		yt = -(uint64_t) y;
8530Sstevel@tonic-gate/ 		negative ^= 1;
8540Sstevel@tonic-gate/ 	} else {
8550Sstevel@tonic-gate/ 		yt = y;
8560Sstevel@tonic-gate/ 	}
8570Sstevel@tonic-gate/ 	r = UDivRem(xt, yt, &rem);
8580Sstevel@tonic-gate/ 	*pmod = (x < 0 ? (int64_t) - rem : rem);
8590Sstevel@tonic-gate/ 	return (negative ? (int64_t) - r : r);
8600Sstevel@tonic-gate/ }
8610Sstevel@tonic-gate	ENTRY(SDivRem)
8620Sstevel@tonic-gate	pushl	%ebp
8630Sstevel@tonic-gate	pushl	%edi
8640Sstevel@tonic-gate	pushl	%esi
8650Sstevel@tonic-gate	subl	$24, %esp
8660Sstevel@tonic-gate	testl	%edx, %edx	/ x
8670Sstevel@tonic-gate	movl	%edx, %edi	/ x, x
8680Sstevel@tonic-gate	js	.LL73
8690Sstevel@tonic-gate	movl	44(%esp), %esi	/ y,
8700Sstevel@tonic-gate	xorl	%ebp, %ebp	/ negative
8710Sstevel@tonic-gate	testl	%esi, %esi
8720Sstevel@tonic-gate	movl	%edx, 12(%esp)	/ x, xt
8730Sstevel@tonic-gate	movl	%eax, 8(%esp)	/ x, xt
8740Sstevel@tonic-gate	movl	40(%esp), %edx	/ y, yt
8750Sstevel@tonic-gate	movl	44(%esp), %ecx	/ y, yt
8760Sstevel@tonic-gate	js	.LL74
8770Sstevel@tonic-gate.LL70:
8780Sstevel@tonic-gate	leal	16(%esp), %eax	/, tmp70
8790Sstevel@tonic-gate	pushl	%eax		/ tmp70
8800Sstevel@tonic-gate	pushl	%ecx		/ yt
8810Sstevel@tonic-gate	pushl	%edx		/ yt
8820Sstevel@tonic-gate	movl	20(%esp), %eax	/ xt, xt
8830Sstevel@tonic-gate	movl	24(%esp), %edx	/ xt, xt
8840Sstevel@tonic-gate	call	UDivRem
8850Sstevel@tonic-gate	movl	%edx, 16(%esp)	/, r
8860Sstevel@tonic-gate	movl	%eax, 12(%esp)	/, r
8870Sstevel@tonic-gate	addl	$12, %esp
8880Sstevel@tonic-gate	testl	%edi, %edi	/ x
8890Sstevel@tonic-gate	movl	16(%esp), %edx	/ rem, rem
8900Sstevel@tonic-gate	movl	20(%esp), %ecx	/ rem, rem
8910Sstevel@tonic-gate	js	.LL75
8920Sstevel@tonic-gate.LL71:
8930Sstevel@tonic-gate	movl	48(%esp), %edi	/ pmod, pmod
8940Sstevel@tonic-gate	testl	%ebp, %ebp	/ negative
8950Sstevel@tonic-gate	movl	%edx, (%edi)	/ rem,* pmod
8960Sstevel@tonic-gate	movl	%ecx, 4(%edi)	/ rem,
8970Sstevel@tonic-gate	movl	(%esp), %eax	/ r, r
8980Sstevel@tonic-gate	movl	4(%esp), %edx	/ r, r
8990Sstevel@tonic-gate	je	.LL72
9000Sstevel@tonic-gate	negl	%eax		/ r
9010Sstevel@tonic-gate	adcl	$0, %edx	/, r
9020Sstevel@tonic-gate	negl	%edx		/ r
9030Sstevel@tonic-gate.LL72:
9040Sstevel@tonic-gate	addl	$24, %esp
9050Sstevel@tonic-gate	popl	%esi
9060Sstevel@tonic-gate	popl	%edi
9070Sstevel@tonic-gate	popl	%ebp
9080Sstevel@tonic-gate	ret
9090Sstevel@tonic-gate	.align	16
9100Sstevel@tonic-gate.LL73:
9110Sstevel@tonic-gate	negl	%eax
9120Sstevel@tonic-gate	adcl	$0, %edx
9130Sstevel@tonic-gate	movl	44(%esp), %esi	/ y,
9140Sstevel@tonic-gate	negl	%edx
9150Sstevel@tonic-gate	testl	%esi, %esi
9160Sstevel@tonic-gate	movl	%edx, 12(%esp)	/, xt
9170Sstevel@tonic-gate	movl	%eax, 8(%esp)	/, xt
9180Sstevel@tonic-gate	movl	$1, %ebp	/, negative
9190Sstevel@tonic-gate	movl	40(%esp), %edx	/ y, yt
9200Sstevel@tonic-gate	movl	44(%esp), %ecx	/ y, yt
9210Sstevel@tonic-gate	jns	.LL70
9220Sstevel@tonic-gate	.align	16
9230Sstevel@tonic-gate.LL74:
9240Sstevel@tonic-gate	negl	%edx		/ yt
9250Sstevel@tonic-gate	adcl	$0, %ecx	/, yt
9260Sstevel@tonic-gate	negl	%ecx		/ yt
9270Sstevel@tonic-gate	xorl	$1, %ebp	/, negative
9280Sstevel@tonic-gate	jmp	.LL70
9290Sstevel@tonic-gate	.align	16
9300Sstevel@tonic-gate.LL75:
9310Sstevel@tonic-gate	negl	%edx		/ rem
9320Sstevel@tonic-gate	adcl	$0, %ecx	/, rem
9330Sstevel@tonic-gate	negl	%ecx		/ rem
9340Sstevel@tonic-gate	jmp	.LL71
9350Sstevel@tonic-gate	SET_SIZE(SDivRem)
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate/*
9380Sstevel@tonic-gate * __divrem64
9390Sstevel@tonic-gate *
9400Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the
9410Sstevel@tonic-gate * quotient in %edx:%eax, and the remainder in %ecx:%esi.  __divrem64
9420Sstevel@tonic-gate * pops the arguments on return.
9430Sstevel@tonic-gate */
9440Sstevel@tonic-gate	ENTRY(__divrem64)
9450Sstevel@tonic-gate	subl	$20, %esp
9460Sstevel@tonic-gate	movl	%esp, %ecx	/, tmp64
9470Sstevel@tonic-gate	movl	24(%esp), %eax	/ x, x
9480Sstevel@tonic-gate	movl	28(%esp), %edx	/ x, x
9490Sstevel@tonic-gate	pushl	%ecx		/ tmp64
9500Sstevel@tonic-gate	pushl	40(%esp)	/ y
9510Sstevel@tonic-gate	pushl	40(%esp)
9520Sstevel@tonic-gate	call	SDivRem
9530Sstevel@tonic-gate	movl	16(%esp), %ecx
9540Sstevel@tonic-gate	movl	12(%esp),%esi	/ rem
9550Sstevel@tonic-gate	addl	$32, %esp
9560Sstevel@tonic-gate	ret	$16
9570Sstevel@tonic-gate	SET_SIZE(__divrem64)
958