xref: /illumos-gate/usr/src/common/util/i386/muldiv.S (revision 55fea89d)
17c478bd9Sstevel@tonic-gate/*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate/*
237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
2789518a1cSdmick#if !defined(lint)
2889518a1cSdmick	.ident	"%Z%%M%	%I%	%E% SMI"
2989518a1cSdmick
3089518a1cSdmick	.file	"muldiv.s"
317c478bd9Sstevel@tonic-gate#endif
327c478bd9Sstevel@tonic-gate
3389518a1cSdmick#if defined(__i386) && !defined(__amd64)
3489518a1cSdmick
3589518a1cSdmick/*
3689518a1cSdmick * Helper routines for 32-bit compilers to perform 64-bit math.
3789518a1cSdmick * These are used both by the Sun and GCC compilers.
3889518a1cSdmick */
3989518a1cSdmick
407c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h>
4189518a1cSdmick#include <sys/asm_misc.h>
4289518a1cSdmick
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate#if defined(__lint)
4589518a1cSdmick#include <sys/types.h>
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate/* ARGSUSED */
487c478bd9Sstevel@tonic-gateint64_t
497c478bd9Sstevel@tonic-gate__mul64(int64_t a, int64_t b)
50*55fea89dSDan Cross{
51*55fea89dSDan Cross	return (0);
527c478bd9Sstevel@tonic-gate}
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate#else   /* __lint */
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate/
577c478bd9Sstevel@tonic-gate/   function __mul64(A,B:Longint):Longint;
587c478bd9Sstevel@tonic-gate/	{Overflow is not checked}
597c478bd9Sstevel@tonic-gate/
607c478bd9Sstevel@tonic-gate/ We essentially do multiply by longhand, using base 2**32 digits.
617c478bd9Sstevel@tonic-gate/               a       b	parameter A
627c478bd9Sstevel@tonic-gate/	     x 	c       d	parameter B
637c478bd9Sstevel@tonic-gate/		---------
647c478bd9Sstevel@tonic-gate/               ad      bd
657c478bd9Sstevel@tonic-gate/       ac	bc
667c478bd9Sstevel@tonic-gate/       -----------------
677c478bd9Sstevel@tonic-gate/       ac	ad+bc	bd
687c478bd9Sstevel@tonic-gate/
697c478bd9Sstevel@tonic-gate/       We can ignore ac and top 32 bits of ad+bc: if <> 0, overflow happened.
707c478bd9Sstevel@tonic-gate/
717c478bd9Sstevel@tonic-gate	ENTRY(__mul64)
727c478bd9Sstevel@tonic-gate	push	%ebp
737c478bd9Sstevel@tonic-gate	mov    	%esp,%ebp
747c478bd9Sstevel@tonic-gate	pushl	%esi
757c478bd9Sstevel@tonic-gate	mov	12(%ebp),%eax	/ A.hi (a)
767c478bd9Sstevel@tonic-gate	mull	16(%ebp)	/ Multiply A.hi by B.lo (produces ad)
777c478bd9Sstevel@tonic-gate	xchg	%ecx,%eax	/ ecx = bottom half of ad.
787c478bd9Sstevel@tonic-gate	movl    8(%ebp),%eax	/ A.Lo (b)
797c478bd9Sstevel@tonic-gate	movl	%eax,%esi	/ Save A.lo for later
807c478bd9Sstevel@tonic-gate	mull	16(%ebp)	/ Multiply A.Lo by B.LO (dx:ax = bd.)
817c478bd9Sstevel@tonic-gate	addl	%edx,%ecx	/ cx is ad
827c478bd9Sstevel@tonic-gate	xchg	%eax,%esi       / esi is bd, eax = A.lo (d)
837c478bd9Sstevel@tonic-gate	mull	20(%ebp)	/ Multiply A.lo * B.hi (producing bc)
847c478bd9Sstevel@tonic-gate	addl	%ecx,%eax	/ Produce ad+bc
857c478bd9Sstevel@tonic-gate	movl	%esi,%edx
867c478bd9Sstevel@tonic-gate	xchg	%eax,%edx
877c478bd9Sstevel@tonic-gate	popl	%esi
887c478bd9Sstevel@tonic-gate	movl	%ebp,%esp
897c478bd9Sstevel@tonic-gate	popl	%ebp
907c478bd9Sstevel@tonic-gate	ret     $16
917c478bd9Sstevel@tonic-gate	SET_SIZE(__mul64)
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate#endif	/* __lint */
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate/*
967c478bd9Sstevel@tonic-gate * C support for 64-bit modulo and division.
977c478bd9Sstevel@tonic-gate * Hand-customized compiler output - see comments for details.
987c478bd9Sstevel@tonic-gate */
997c478bd9Sstevel@tonic-gate#if defined(__lint)
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate/* ARGSUSED */
1027c478bd9Sstevel@tonic-gateuint64_t
1037c478bd9Sstevel@tonic-gate__udiv64(uint64_t a, uint64_t b)
1047c478bd9Sstevel@tonic-gate{ return (0); }
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate/* ARGSUSED */
1077c478bd9Sstevel@tonic-gateuint64_t
1087c478bd9Sstevel@tonic-gate__urem64(int64_t a, int64_t b)
1097c478bd9Sstevel@tonic-gate{ return (0); }
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate/* ARGSUSED */
1127c478bd9Sstevel@tonic-gateint64_t
1137c478bd9Sstevel@tonic-gate__div64(int64_t a, int64_t b)
1147c478bd9Sstevel@tonic-gate{ return (0); }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate/* ARGSUSED */
1177c478bd9Sstevel@tonic-gateint64_t
1187c478bd9Sstevel@tonic-gate__rem64(int64_t a, int64_t b)
1197c478bd9Sstevel@tonic-gate{ return (0); }
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate#else	/* __lint */
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate/ /*
1247c478bd9Sstevel@tonic-gate/  * Unsigned division with remainder.
1257c478bd9Sstevel@tonic-gate/  * Divide two uint64_ts, and calculate remainder.
1267c478bd9Sstevel@tonic-gate/  */
1277c478bd9Sstevel@tonic-gate/ uint64_t
1287c478bd9Sstevel@tonic-gate/ UDivRem(uint64_t x, uint64_t y, uint64_t * pmod)
1297c478bd9Sstevel@tonic-gate/ {
1307c478bd9Sstevel@tonic-gate/ 	/* simple cases: y is a single uint32_t */
1317c478bd9Sstevel@tonic-gate/ 	if (HI(y) == 0) {
1327c478bd9Sstevel@tonic-gate/ 		uint32_t	div_hi, div_rem;
1337c478bd9Sstevel@tonic-gate/ 		uint32_t 	q0, q1;
134*55fea89dSDan Cross/
1357c478bd9Sstevel@tonic-gate/ 		/* calculate q1 */
1367c478bd9Sstevel@tonic-gate/ 		if (HI(x) < LO(y)) {
1377c478bd9Sstevel@tonic-gate/ 			/* result is a single uint32_t, use one division */
1387c478bd9Sstevel@tonic-gate/ 			q1 = 0;
1397c478bd9Sstevel@tonic-gate/ 			div_hi = HI(x);
1407c478bd9Sstevel@tonic-gate/ 		} else {
1417c478bd9Sstevel@tonic-gate/ 			/* result is a double uint32_t, use two divisions */
1427c478bd9Sstevel@tonic-gate/ 			A_DIV32(HI(x), 0, LO(y), q1, div_hi);
1437c478bd9Sstevel@tonic-gate/ 		}
144*55fea89dSDan Cross/
1457c478bd9Sstevel@tonic-gate/ 		/* calculate q0 and remainder */
1467c478bd9Sstevel@tonic-gate/ 		A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
147*55fea89dSDan Cross/
1487c478bd9Sstevel@tonic-gate/ 		/* return remainder */
1497c478bd9Sstevel@tonic-gate/ 		*pmod = div_rem;
150*55fea89dSDan Cross/
1517c478bd9Sstevel@tonic-gate/ 		/* return result */
1527c478bd9Sstevel@tonic-gate/ 		return (HILO(q1, q0));
153*55fea89dSDan Cross/
1547c478bd9Sstevel@tonic-gate/ 	} else if (HI(x) < HI(y)) {
1557c478bd9Sstevel@tonic-gate/ 		/* HI(x) < HI(y) => x < y => result is 0 */
156*55fea89dSDan Cross/
1577c478bd9Sstevel@tonic-gate/ 		/* return remainder */
1587c478bd9Sstevel@tonic-gate/ 		*pmod = x;
159*55fea89dSDan Cross/
1607c478bd9Sstevel@tonic-gate/ 		/* return result */
1617c478bd9Sstevel@tonic-gate/ 		return (0);
162*55fea89dSDan Cross/
1637c478bd9Sstevel@tonic-gate/ 	} else {
1647c478bd9Sstevel@tonic-gate/ 		/*
1657c478bd9Sstevel@tonic-gate/ 		 * uint64_t by uint64_t division, resulting in a one-uint32_t
1667c478bd9Sstevel@tonic-gate/ 		 * result
1677c478bd9Sstevel@tonic-gate/ 		 */
1687c478bd9Sstevel@tonic-gate/ 		uint32_t		y0, y1;
1697c478bd9Sstevel@tonic-gate/ 		uint32_t		x1, x0;
1707c478bd9Sstevel@tonic-gate/ 		uint32_t		q0;
1717c478bd9Sstevel@tonic-gate/ 		uint32_t		normshift;
172*55fea89dSDan Cross/
1737c478bd9Sstevel@tonic-gate/ 		/* normalize by shifting x and y so MSB(y) == 1 */
1747c478bd9Sstevel@tonic-gate/ 		HIBIT(HI(y), normshift);	/* index of highest 1 bit */
1757c478bd9Sstevel@tonic-gate/ 		normshift = 31 - normshift;
176*55fea89dSDan Cross/
1777c478bd9Sstevel@tonic-gate/ 		if (normshift == 0) {
1787c478bd9Sstevel@tonic-gate/ 			/* no shifting needed, and x < 2*y so q <= 1 */
1797c478bd9Sstevel@tonic-gate/ 			y1 = HI(y);
1807c478bd9Sstevel@tonic-gate/ 			y0 = LO(y);
1817c478bd9Sstevel@tonic-gate/ 			x1 = HI(x);
1827c478bd9Sstevel@tonic-gate/ 			x0 = LO(x);
183*55fea89dSDan Cross/
1847c478bd9Sstevel@tonic-gate/ 			/* if x >= y then q = 1 (note x1 >= y1) */
1857c478bd9Sstevel@tonic-gate/ 			if (x1 > y1 || x0 >= y0) {
1867c478bd9Sstevel@tonic-gate/ 				q0 = 1;
1877c478bd9Sstevel@tonic-gate/ 				/* subtract y from x to get remainder */
1887c478bd9Sstevel@tonic-gate/ 				A_SUB2(y0, y1, x0, x1);
1897c478bd9Sstevel@tonic-gate/ 			} else {
1907c478bd9Sstevel@tonic-gate/ 				q0 = 0;
1917c478bd9Sstevel@tonic-gate/ 			}
192*55fea89dSDan Cross/
1937c478bd9Sstevel@tonic-gate/ 			/* return remainder */
1947c478bd9Sstevel@tonic-gate/ 			*pmod = HILO(x1, x0);
195*55fea89dSDan Cross/
1967c478bd9Sstevel@tonic-gate/ 			/* return result */
1977c478bd9Sstevel@tonic-gate/ 			return (q0);
198*55fea89dSDan Cross/
1997c478bd9Sstevel@tonic-gate/ 		} else {
2007c478bd9Sstevel@tonic-gate/ 			/*
2017c478bd9Sstevel@tonic-gate/ 			 * the last case: result is one uint32_t, but we need to
2027c478bd9Sstevel@tonic-gate/ 			 * normalize
2037c478bd9Sstevel@tonic-gate/ 			 */
2047c478bd9Sstevel@tonic-gate/ 			uint64_t	dt;
2057c478bd9Sstevel@tonic-gate/ 			uint32_t		t0, t1, x2;
206*55fea89dSDan Cross/
2077c478bd9Sstevel@tonic-gate/ 			/* normalize y */
2087c478bd9Sstevel@tonic-gate/ 			dt = (y << normshift);
2097c478bd9Sstevel@tonic-gate/ 			y1 = HI(dt);
2107c478bd9Sstevel@tonic-gate/ 			y0 = LO(dt);
211*55fea89dSDan Cross/
2127c478bd9Sstevel@tonic-gate/ 			/* normalize x (we need 3 uint32_ts!!!) */
2137c478bd9Sstevel@tonic-gate/ 			x2 = (HI(x) >> (32 - normshift));
2147c478bd9Sstevel@tonic-gate/ 			dt = (x << normshift);
2157c478bd9Sstevel@tonic-gate/ 			x1 = HI(dt);
2167c478bd9Sstevel@tonic-gate/ 			x0 = LO(dt);
217*55fea89dSDan Cross/
2187c478bd9Sstevel@tonic-gate/ 			/* estimate q0, and reduce x to a two uint32_t value */
2197c478bd9Sstevel@tonic-gate/ 			A_DIV32(x1, x2, y1, q0, x1);
220*55fea89dSDan Cross/
2217c478bd9Sstevel@tonic-gate/ 			/* adjust q0 down if too high */
2227c478bd9Sstevel@tonic-gate/ 			/*
2237c478bd9Sstevel@tonic-gate/ 			 * because of the limited range of x2 we can only be
2247c478bd9Sstevel@tonic-gate/ 			 * one off
2257c478bd9Sstevel@tonic-gate/ 			 */
2267c478bd9Sstevel@tonic-gate/ 			A_MUL32(y0, q0, t0, t1);
2277c478bd9Sstevel@tonic-gate/ 			if (t1 > x1 || (t1 == x1 && t0 > x0)) {
2287c478bd9Sstevel@tonic-gate/ 				q0--;
2297c478bd9Sstevel@tonic-gate/ 				A_SUB2(y0, y1, t0, t1);
2307c478bd9Sstevel@tonic-gate/ 			}
2317c478bd9Sstevel@tonic-gate/ 			/* return remainder */
2327c478bd9Sstevel@tonic-gate/ 			/* subtract product from x to get remainder */
2337c478bd9Sstevel@tonic-gate/ 			A_SUB2(t0, t1, x0, x1);
2347c478bd9Sstevel@tonic-gate/ 			*pmod = (HILO(x1, x0) >> normshift);
235*55fea89dSDan Cross/
2367c478bd9Sstevel@tonic-gate/ 			/* return result */
2377c478bd9Sstevel@tonic-gate/ 			return (q0);
2387c478bd9Sstevel@tonic-gate/ 		}
2397c478bd9Sstevel@tonic-gate/ 	}
2407c478bd9Sstevel@tonic-gate/ }
2417c478bd9Sstevel@tonic-gate	ENTRY(UDivRem)
2427c478bd9Sstevel@tonic-gate	pushl	%ebp
2437c478bd9Sstevel@tonic-gate	pushl	%edi
2447c478bd9Sstevel@tonic-gate	pushl	%esi
2457c478bd9Sstevel@tonic-gate	subl	$48, %esp
2467c478bd9Sstevel@tonic-gate	movl	68(%esp), %edi	/ y,
2477c478bd9Sstevel@tonic-gate	testl	%edi, %edi	/ tmp63
2487c478bd9Sstevel@tonic-gate	movl	%eax, 40(%esp)	/ x, x
2497c478bd9Sstevel@tonic-gate	movl	%edx, 44(%esp)	/ x, x
2507c478bd9Sstevel@tonic-gate	movl	%edi, %esi	/, tmp62
2517c478bd9Sstevel@tonic-gate	movl	%edi, %ecx	/ tmp62, tmp63
2527c478bd9Sstevel@tonic-gate	jne	.LL2
2537c478bd9Sstevel@tonic-gate	movl	%edx, %eax	/, tmp68
2547c478bd9Sstevel@tonic-gate	cmpl	64(%esp), %eax	/ y, tmp68
2557c478bd9Sstevel@tonic-gate	jae	.LL21
2567c478bd9Sstevel@tonic-gate.LL4:
2577c478bd9Sstevel@tonic-gate	movl	72(%esp), %ebp	/ pmod,
2587c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
2597c478bd9Sstevel@tonic-gate	movl	40(%esp), %eax	/ x, q0
2607c478bd9Sstevel@tonic-gate	movl	%ecx, %edi	/ <result>, <result>
2617c478bd9Sstevel@tonic-gate	divl	64(%esp)	/ y
2627c478bd9Sstevel@tonic-gate	movl	%edx, (%ebp)	/ div_rem,
2637c478bd9Sstevel@tonic-gate	xorl	%edx, %edx	/ q0
2647c478bd9Sstevel@tonic-gate	addl	%eax, %esi	/ q0, <result>
2657c478bd9Sstevel@tonic-gate	movl	$0, 4(%ebp)
2667c478bd9Sstevel@tonic-gate	adcl	%edx, %edi	/ q0, <result>
2677c478bd9Sstevel@tonic-gate	addl	$48, %esp
2687c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
2697c478bd9Sstevel@tonic-gate	popl	%esi
2707c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
2717c478bd9Sstevel@tonic-gate	popl	%edi
2727c478bd9Sstevel@tonic-gate	popl	%ebp
2737c478bd9Sstevel@tonic-gate	ret
2747c478bd9Sstevel@tonic-gate	.align	16
2757c478bd9Sstevel@tonic-gate.LL2:
2767c478bd9Sstevel@tonic-gate	movl	44(%esp), %eax	/ x,
2777c478bd9Sstevel@tonic-gate	xorl	%edx, %edx
2787c478bd9Sstevel@tonic-gate	cmpl	%esi, %eax	/ tmp62, tmp5
2797c478bd9Sstevel@tonic-gate	movl	%eax, 32(%esp)	/ tmp5,
2807c478bd9Sstevel@tonic-gate	movl	%edx, 36(%esp)
2817c478bd9Sstevel@tonic-gate	jae	.LL6
2827c478bd9Sstevel@tonic-gate	movl	72(%esp), %esi	/ pmod,
2837c478bd9Sstevel@tonic-gate	movl	40(%esp), %ebp	/ x,
2847c478bd9Sstevel@tonic-gate	movl	44(%esp), %ecx	/ x,
2857c478bd9Sstevel@tonic-gate	movl	%ebp, (%esi)
2867c478bd9Sstevel@tonic-gate	movl	%ecx, 4(%esi)
2877c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
2887c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
2897c478bd9Sstevel@tonic-gate.LL22:
2907c478bd9Sstevel@tonic-gate	addl	$48, %esp
2917c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
2927c478bd9Sstevel@tonic-gate	popl	%esi
2937c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
2947c478bd9Sstevel@tonic-gate	popl	%edi
2957c478bd9Sstevel@tonic-gate	popl	%ebp
2967c478bd9Sstevel@tonic-gate	ret
2977c478bd9Sstevel@tonic-gate	.align	16
2987c478bd9Sstevel@tonic-gate.LL21:
2997c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ tmp63, div_hi
3007c478bd9Sstevel@tonic-gate	divl	64(%esp)	/ y
3017c478bd9Sstevel@tonic-gate	movl	%eax, %ecx	/, q1
3027c478bd9Sstevel@tonic-gate	jmp	.LL4
3037c478bd9Sstevel@tonic-gate	.align	16
3047c478bd9Sstevel@tonic-gate.LL6:
3057c478bd9Sstevel@tonic-gate	movl	$31, %edi	/, tmp87
3067c478bd9Sstevel@tonic-gate	bsrl	%esi,%edx	/ tmp62, normshift
3077c478bd9Sstevel@tonic-gate	subl	%edx, %edi	/ normshift, tmp87
3087c478bd9Sstevel@tonic-gate	movl	%edi, 28(%esp)	/ tmp87,
3097c478bd9Sstevel@tonic-gate	jne	.LL8
3107c478bd9Sstevel@tonic-gate	movl	32(%esp), %edx	/, x1
3117c478bd9Sstevel@tonic-gate	cmpl	%ecx, %edx	/ y1, x1
3127c478bd9Sstevel@tonic-gate	movl	64(%esp), %edi	/ y, y0
3137c478bd9Sstevel@tonic-gate	movl	40(%esp), %esi	/ x, x0
3147c478bd9Sstevel@tonic-gate	ja	.LL10
3157c478bd9Sstevel@tonic-gate	xorl	%ebp, %ebp	/ q0
3167c478bd9Sstevel@tonic-gate	cmpl	%edi, %esi	/ y0, x0
3177c478bd9Sstevel@tonic-gate	jb	.LL11
3187c478bd9Sstevel@tonic-gate.LL10:
3197c478bd9Sstevel@tonic-gate	movl	$1, %ebp	/, q0
3207c478bd9Sstevel@tonic-gate	subl	%edi,%esi	/ y0, x0
3217c478bd9Sstevel@tonic-gate	sbbl	%ecx,%edx	/ tmp63, x1
3227c478bd9Sstevel@tonic-gate.LL11:
3237c478bd9Sstevel@tonic-gate	movl	%edx, %ecx	/ x1, x1
3247c478bd9Sstevel@tonic-gate	xorl	%edx, %edx	/ x1
3257c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ x0
3267c478bd9Sstevel@tonic-gate	addl	%esi, %edx	/ x0, x1
3277c478bd9Sstevel@tonic-gate	adcl	%edi, %ecx	/ x0, x1
3287c478bd9Sstevel@tonic-gate	movl	72(%esp), %esi	/ pmod,
3297c478bd9Sstevel@tonic-gate	movl	%edx, (%esi)	/ x1,
3307c478bd9Sstevel@tonic-gate	movl	%ecx, 4(%esi)	/ x1,
3317c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
3327c478bd9Sstevel@tonic-gate	movl	%ebp, %esi	/ q0, <result>
3337c478bd9Sstevel@tonic-gate	jmp	.LL22
3347c478bd9Sstevel@tonic-gate	.align	16
3357c478bd9Sstevel@tonic-gate.LL8:
3367c478bd9Sstevel@tonic-gate	movb	28(%esp), %cl
3377c478bd9Sstevel@tonic-gate	movl	64(%esp), %esi	/ y, dt
3387c478bd9Sstevel@tonic-gate	movl	68(%esp), %edi	/ y, dt
3397c478bd9Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
3407c478bd9Sstevel@tonic-gate	sall	%cl, %esi	/, dt
3417c478bd9Sstevel@tonic-gate	andl	$32, %ecx
3427c478bd9Sstevel@tonic-gate	jne	.LL23
3437c478bd9Sstevel@tonic-gate.LL17:
3447c478bd9Sstevel@tonic-gate	movl	$32, %ecx	/, tmp102
3457c478bd9Sstevel@tonic-gate	subl	28(%esp), %ecx	/, tmp102
3467c478bd9Sstevel@tonic-gate	movl	%esi, %ebp	/ dt, y0
3477c478bd9Sstevel@tonic-gate	movl	32(%esp), %esi
3487c478bd9Sstevel@tonic-gate	shrl	%cl, %esi	/ tmp102,
3497c478bd9Sstevel@tonic-gate	movl	%edi, 24(%esp)	/ tmp99,
3507c478bd9Sstevel@tonic-gate	movb	28(%esp), %cl
3517c478bd9Sstevel@tonic-gate	movl	%esi, 12(%esp)	/, x2
3527c478bd9Sstevel@tonic-gate	movl	44(%esp), %edi	/ x, dt
3537c478bd9Sstevel@tonic-gate	movl	40(%esp), %esi	/ x, dt
3547c478bd9Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
3557c478bd9Sstevel@tonic-gate	sall	%cl, %esi	/, dt
3567c478bd9Sstevel@tonic-gate	andl	$32, %ecx
3577c478bd9Sstevel@tonic-gate	je	.LL18
3587c478bd9Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
3597c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
3607c478bd9Sstevel@tonic-gate.LL18:
3617c478bd9Sstevel@tonic-gate	movl	%edi, %ecx	/ dt,
3627c478bd9Sstevel@tonic-gate	movl	%edi, %eax	/ tmp2,
3637c478bd9Sstevel@tonic-gate	movl	%ecx, (%esp)
3647c478bd9Sstevel@tonic-gate	movl	12(%esp), %edx	/ x2,
3657c478bd9Sstevel@tonic-gate	divl	24(%esp)
3667c478bd9Sstevel@tonic-gate	movl	%edx, %ecx	/, x1
3677c478bd9Sstevel@tonic-gate	xorl	%edi, %edi
3687c478bd9Sstevel@tonic-gate	movl	%eax, 20(%esp)
3697c478bd9Sstevel@tonic-gate	movl	%ebp, %eax	/ y0, t0
3707c478bd9Sstevel@tonic-gate	mull	20(%esp)
3717c478bd9Sstevel@tonic-gate	cmpl	%ecx, %edx	/ x1, t1
3727c478bd9Sstevel@tonic-gate	movl	%edi, 4(%esp)
3737c478bd9Sstevel@tonic-gate	ja	.LL14
3747c478bd9Sstevel@tonic-gate	je	.LL24
3757c478bd9Sstevel@tonic-gate.LL15:
3767c478bd9Sstevel@tonic-gate	movl	%ecx, %edi	/ x1,
3777c478bd9Sstevel@tonic-gate	subl	%eax,%esi	/ t0, x0
3787c478bd9Sstevel@tonic-gate	sbbl	%edx,%edi	/ t1,
3797c478bd9Sstevel@tonic-gate	movl	%edi, %eax	/, x1
3807c478bd9Sstevel@tonic-gate	movl	%eax, %edx	/ x1, x1
3817c478bd9Sstevel@tonic-gate	xorl	%eax, %eax	/ x1
3827c478bd9Sstevel@tonic-gate	xorl	%ebp, %ebp	/ x0
3837c478bd9Sstevel@tonic-gate	addl	%esi, %eax	/ x0, x1
3847c478bd9Sstevel@tonic-gate	adcl	%ebp, %edx	/ x0, x1
3857c478bd9Sstevel@tonic-gate	movb	28(%esp), %cl
3867c478bd9Sstevel@tonic-gate	shrdl	%edx, %eax	/, x1, x1
3877c478bd9Sstevel@tonic-gate	shrl	%cl, %edx	/, x1
3887c478bd9Sstevel@tonic-gate	andl	$32, %ecx
3897c478bd9Sstevel@tonic-gate	je	.LL16
3907c478bd9Sstevel@tonic-gate	movl	%edx, %eax	/ x1, x1
3917c478bd9Sstevel@tonic-gate	xorl	%edx, %edx	/ x1
3927c478bd9Sstevel@tonic-gate.LL16:
3937c478bd9Sstevel@tonic-gate	movl	72(%esp), %ecx	/ pmod,
3947c478bd9Sstevel@tonic-gate	movl	20(%esp), %esi	/, <result>
3957c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
3967c478bd9Sstevel@tonic-gate	movl	%eax, (%ecx)	/ x1,
3977c478bd9Sstevel@tonic-gate	movl	%edx, 4(%ecx)	/ x1,
3987c478bd9Sstevel@tonic-gate	jmp	.LL22
3997c478bd9Sstevel@tonic-gate	.align	16
4007c478bd9Sstevel@tonic-gate.LL24:
4017c478bd9Sstevel@tonic-gate	cmpl	%esi, %eax	/ x0, t0
4027c478bd9Sstevel@tonic-gate	jbe	.LL15
4037c478bd9Sstevel@tonic-gate.LL14:
4047c478bd9Sstevel@tonic-gate	decl	20(%esp)
4057c478bd9Sstevel@tonic-gate	subl	%ebp,%eax	/ y0, t0
4067c478bd9Sstevel@tonic-gate	sbbl	24(%esp),%edx	/, t1
4077c478bd9Sstevel@tonic-gate	jmp	.LL15
4087c478bd9Sstevel@tonic-gate.LL23:
4097c478bd9Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
4107c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
4117c478bd9Sstevel@tonic-gate	jmp	.LL17
4127c478bd9Sstevel@tonic-gate	SET_SIZE(UDivRem)
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate/*
4157c478bd9Sstevel@tonic-gate * Unsigned division without remainder.
4167c478bd9Sstevel@tonic-gate */
4177c478bd9Sstevel@tonic-gate/ uint64_t
4187c478bd9Sstevel@tonic-gate/ UDiv(uint64_t x, uint64_t y)
4197c478bd9Sstevel@tonic-gate/ {
4207c478bd9Sstevel@tonic-gate/ 	if (HI(y) == 0) {
4217c478bd9Sstevel@tonic-gate/ 		/* simple cases: y is a single uint32_t */
4227c478bd9Sstevel@tonic-gate/ 		uint32_t	div_hi, div_rem;
4237c478bd9Sstevel@tonic-gate/ 		uint32_t	q0, q1;
424*55fea89dSDan Cross/
4257c478bd9Sstevel@tonic-gate/ 		/* calculate q1 */
4267c478bd9Sstevel@tonic-gate/ 		if (HI(x) < LO(y)) {
4277c478bd9Sstevel@tonic-gate/ 			/* result is a single uint32_t, use one division */
4287c478bd9Sstevel@tonic-gate/ 			q1 = 0;
4297c478bd9Sstevel@tonic-gate/ 			div_hi = HI(x);
4307c478bd9Sstevel@tonic-gate/ 		} else {
4317c478bd9Sstevel@tonic-gate/ 			/* result is a double uint32_t, use two divisions */
4327c478bd9Sstevel@tonic-gate/ 			A_DIV32(HI(x), 0, LO(y), q1, div_hi);
4337c478bd9Sstevel@tonic-gate/ 		}
434*55fea89dSDan Cross/
4357c478bd9Sstevel@tonic-gate/ 		/* calculate q0 and remainder */
4367c478bd9Sstevel@tonic-gate/ 		A_DIV32(LO(x), div_hi, LO(y), q0, div_rem);
437*55fea89dSDan Cross/
4387c478bd9Sstevel@tonic-gate/ 		/* return result */
4397c478bd9Sstevel@tonic-gate/ 		return (HILO(q1, q0));
440*55fea89dSDan Cross/
4417c478bd9Sstevel@tonic-gate/ 	} else if (HI(x) < HI(y)) {
4427c478bd9Sstevel@tonic-gate/ 		/* HI(x) < HI(y) => x < y => result is 0 */
443*55fea89dSDan Cross/
4447c478bd9Sstevel@tonic-gate/ 		/* return result */
4457c478bd9Sstevel@tonic-gate/ 		return (0);
446*55fea89dSDan Cross/
4477c478bd9Sstevel@tonic-gate/ 	} else {
4487c478bd9Sstevel@tonic-gate/ 		/*
4497c478bd9Sstevel@tonic-gate/ 		 * uint64_t by uint64_t division, resulting in a one-uint32_t
4507c478bd9Sstevel@tonic-gate/ 		 * result
4517c478bd9Sstevel@tonic-gate/ 		 */
4527c478bd9Sstevel@tonic-gate/ 		uint32_t		y0, y1;
4537c478bd9Sstevel@tonic-gate/ 		uint32_t		x1, x0;
4547c478bd9Sstevel@tonic-gate/ 		uint32_t		q0;
4557c478bd9Sstevel@tonic-gate/ 		unsigned		normshift;
456*55fea89dSDan Cross/
4577c478bd9Sstevel@tonic-gate/ 		/* normalize by shifting x and y so MSB(y) == 1 */
4587c478bd9Sstevel@tonic-gate/ 		HIBIT(HI(y), normshift);	/* index of highest 1 bit */
4597c478bd9Sstevel@tonic-gate/ 		normshift = 31 - normshift;
460*55fea89dSDan Cross/
4617c478bd9Sstevel@tonic-gate/ 		if (normshift == 0) {
4627c478bd9Sstevel@tonic-gate/ 			/* no shifting needed, and x < 2*y so q <= 1 */
4637c478bd9Sstevel@tonic-gate/ 			y1 = HI(y);
4647c478bd9Sstevel@tonic-gate/ 			y0 = LO(y);
4657c478bd9Sstevel@tonic-gate/ 			x1 = HI(x);
4667c478bd9Sstevel@tonic-gate/ 			x0 = LO(x);
467*55fea89dSDan Cross/
4687c478bd9Sstevel@tonic-gate/ 			/* if x >= y then q = 1 (note x1 >= y1) */
4697c478bd9Sstevel@tonic-gate/ 			if (x1 > y1 || x0 >= y0) {
4707c478bd9Sstevel@tonic-gate/ 				q0 = 1;
4717c478bd9Sstevel@tonic-gate/ 				/* subtract y from x to get remainder */
4727c478bd9Sstevel@tonic-gate/ 				/* A_SUB2(y0, y1, x0, x1); */
4737c478bd9Sstevel@tonic-gate/ 			} else {
4747c478bd9Sstevel@tonic-gate/ 				q0 = 0;
4757c478bd9Sstevel@tonic-gate/ 			}
476*55fea89dSDan Cross/
4777c478bd9Sstevel@tonic-gate/ 			/* return result */
4787c478bd9Sstevel@tonic-gate/ 			return (q0);
479*55fea89dSDan Cross/
4807c478bd9Sstevel@tonic-gate/ 		} else {
4817c478bd9Sstevel@tonic-gate/ 			/*
4827c478bd9Sstevel@tonic-gate/ 			 * the last case: result is one uint32_t, but we need to
4837c478bd9Sstevel@tonic-gate/ 			 * normalize
4847c478bd9Sstevel@tonic-gate/ 			 */
4857c478bd9Sstevel@tonic-gate/ 			uint64_t	dt;
4867c478bd9Sstevel@tonic-gate/ 			uint32_t		t0, t1, x2;
487*55fea89dSDan Cross/
4887c478bd9Sstevel@tonic-gate/ 			/* normalize y */
4897c478bd9Sstevel@tonic-gate/ 			dt = (y << normshift);
4907c478bd9Sstevel@tonic-gate/ 			y1 = HI(dt);
4917c478bd9Sstevel@tonic-gate/ 			y0 = LO(dt);
492*55fea89dSDan Cross/
4937c478bd9Sstevel@tonic-gate/ 			/* normalize x (we need 3 uint32_ts!!!) */
4947c478bd9Sstevel@tonic-gate/ 			x2 = (HI(x) >> (32 - normshift));
4957c478bd9Sstevel@tonic-gate/ 			dt = (x << normshift);
4967c478bd9Sstevel@tonic-gate/ 			x1 = HI(dt);
4977c478bd9Sstevel@tonic-gate/ 			x0 = LO(dt);
498*55fea89dSDan Cross/
4997c478bd9Sstevel@tonic-gate/ 			/* estimate q0, and reduce x to a two uint32_t value */
5007c478bd9Sstevel@tonic-gate/ 			A_DIV32(x1, x2, y1, q0, x1);
501*55fea89dSDan Cross/
5027c478bd9Sstevel@tonic-gate/ 			/* adjust q0 down if too high */
5037c478bd9Sstevel@tonic-gate/ 			/*
5047c478bd9Sstevel@tonic-gate/ 			 * because of the limited range of x2 we can only be
5057c478bd9Sstevel@tonic-gate/ 			 * one off
5067c478bd9Sstevel@tonic-gate/ 			 */
5077c478bd9Sstevel@tonic-gate/ 			A_MUL32(y0, q0, t0, t1);
5087c478bd9Sstevel@tonic-gate/ 			if (t1 > x1 || (t1 == x1 && t0 > x0)) {
5097c478bd9Sstevel@tonic-gate/ 				q0--;
5107c478bd9Sstevel@tonic-gate/ 			}
5117c478bd9Sstevel@tonic-gate/ 			/* return result */
5127c478bd9Sstevel@tonic-gate/ 			return (q0);
5137c478bd9Sstevel@tonic-gate/ 		}
5147c478bd9Sstevel@tonic-gate/ 	}
5157c478bd9Sstevel@tonic-gate/ }
5167c478bd9Sstevel@tonic-gate	ENTRY(UDiv)
5177c478bd9Sstevel@tonic-gate	pushl	%ebp
5187c478bd9Sstevel@tonic-gate	pushl	%edi
5197c478bd9Sstevel@tonic-gate	pushl	%esi
5207c478bd9Sstevel@tonic-gate	subl	$40, %esp
5217c478bd9Sstevel@tonic-gate	movl	%edx, 36(%esp)	/ x, x
5227c478bd9Sstevel@tonic-gate	movl	60(%esp), %edx	/ y,
5237c478bd9Sstevel@tonic-gate	testl	%edx, %edx	/ tmp62
5247c478bd9Sstevel@tonic-gate	movl	%eax, 32(%esp)	/ x, x
5257c478bd9Sstevel@tonic-gate	movl	%edx, %ecx	/ tmp61, tmp62
5267c478bd9Sstevel@tonic-gate	movl	%edx, %eax	/, tmp61
5277c478bd9Sstevel@tonic-gate	jne	.LL26
5287c478bd9Sstevel@tonic-gate	movl	36(%esp), %esi	/ x,
5297c478bd9Sstevel@tonic-gate	cmpl	56(%esp), %esi	/ y, tmp67
5307c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/, tmp67
5317c478bd9Sstevel@tonic-gate	movl	%esi, %edx	/ tmp67, div_hi
5327c478bd9Sstevel@tonic-gate	jb	.LL28
5337c478bd9Sstevel@tonic-gate	movl	%ecx, %edx	/ tmp62, div_hi
5347c478bd9Sstevel@tonic-gate	divl	56(%esp)	/ y
5357c478bd9Sstevel@tonic-gate	movl	%eax, %ecx	/, q1
5367c478bd9Sstevel@tonic-gate.LL28:
5377c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
5387c478bd9Sstevel@tonic-gate	movl	%ecx, %edi	/ <result>, <result>
5397c478bd9Sstevel@tonic-gate	movl	32(%esp), %eax	/ x, q0
5407c478bd9Sstevel@tonic-gate	xorl	%ecx, %ecx	/ q0
5417c478bd9Sstevel@tonic-gate	divl	56(%esp)	/ y
5427c478bd9Sstevel@tonic-gate	addl	%eax, %esi	/ q0, <result>
5437c478bd9Sstevel@tonic-gate	adcl	%ecx, %edi	/ q0, <result>
5447c478bd9Sstevel@tonic-gate.LL25:
5457c478bd9Sstevel@tonic-gate	addl	$40, %esp
5467c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
5477c478bd9Sstevel@tonic-gate	popl	%esi
5487c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
5497c478bd9Sstevel@tonic-gate	popl	%edi
5507c478bd9Sstevel@tonic-gate	popl	%ebp
5517c478bd9Sstevel@tonic-gate	ret
5527c478bd9Sstevel@tonic-gate	.align	16
5537c478bd9Sstevel@tonic-gate.LL26:
5547c478bd9Sstevel@tonic-gate	movl	36(%esp), %esi	/ x,
5557c478bd9Sstevel@tonic-gate	xorl	%edi, %edi
5567c478bd9Sstevel@tonic-gate	movl	%esi, 24(%esp)	/ tmp1,
5577c478bd9Sstevel@tonic-gate	movl	%edi, 28(%esp)
5587c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ <result>
5597c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
5607c478bd9Sstevel@tonic-gate	cmpl	%eax, 24(%esp)	/ tmp61,
5617c478bd9Sstevel@tonic-gate	jb	.LL25
5627c478bd9Sstevel@tonic-gate	bsrl	%eax,%ebp	/ tmp61, normshift
5637c478bd9Sstevel@tonic-gate	movl	$31, %eax	/, tmp85
5647c478bd9Sstevel@tonic-gate	subl	%ebp, %eax	/ normshift, normshift
5657c478bd9Sstevel@tonic-gate	jne	.LL32
5667c478bd9Sstevel@tonic-gate	movl	24(%esp), %eax	/, x1
5677c478bd9Sstevel@tonic-gate	cmpl	%ecx, %eax	/ tmp62, x1
5687c478bd9Sstevel@tonic-gate	movl	56(%esp), %esi	/ y, y0
5697c478bd9Sstevel@tonic-gate	movl	32(%esp), %edx	/ x, x0
5707c478bd9Sstevel@tonic-gate	ja	.LL34
5717c478bd9Sstevel@tonic-gate	xorl	%eax, %eax	/ q0
5727c478bd9Sstevel@tonic-gate	cmpl	%esi, %edx	/ y0, x0
5737c478bd9Sstevel@tonic-gate	jb	.LL35
5747c478bd9Sstevel@tonic-gate.LL34:
5757c478bd9Sstevel@tonic-gate	movl	$1, %eax	/, q0
5767c478bd9Sstevel@tonic-gate.LL35:
5777c478bd9Sstevel@tonic-gate	movl	%eax, %esi	/ q0, <result>
5787c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
5797c478bd9Sstevel@tonic-gate.LL45:
5807c478bd9Sstevel@tonic-gate	addl	$40, %esp
5817c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ <result>, <result>
5827c478bd9Sstevel@tonic-gate	popl	%esi
5837c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ <result>, <result>
5847c478bd9Sstevel@tonic-gate	popl	%edi
5857c478bd9Sstevel@tonic-gate	popl	%ebp
5867c478bd9Sstevel@tonic-gate	ret
5877c478bd9Sstevel@tonic-gate	.align	16
5887c478bd9Sstevel@tonic-gate.LL32:
5897c478bd9Sstevel@tonic-gate	movb	%al, %cl
5907c478bd9Sstevel@tonic-gate	movl	56(%esp), %esi	/ y,
5917c478bd9Sstevel@tonic-gate	movl	60(%esp), %edi	/ y,
5927c478bd9Sstevel@tonic-gate	shldl	%esi, %edi
5937c478bd9Sstevel@tonic-gate	sall	%cl, %esi
5947c478bd9Sstevel@tonic-gate	andl	$32, %ecx
5957c478bd9Sstevel@tonic-gate	jne	.LL43
5967c478bd9Sstevel@tonic-gate.LL40:
5977c478bd9Sstevel@tonic-gate	movl	$32, %ecx	/, tmp96
5987c478bd9Sstevel@tonic-gate	subl	%eax, %ecx	/ normshift, tmp96
5997c478bd9Sstevel@tonic-gate	movl	%edi, %edx
6007c478bd9Sstevel@tonic-gate	movl	%edi, 20(%esp)	/, dt
6017c478bd9Sstevel@tonic-gate	movl	24(%esp), %ebp	/, x2
6027c478bd9Sstevel@tonic-gate	xorl	%edi, %edi
6037c478bd9Sstevel@tonic-gate	shrl	%cl, %ebp	/ tmp96, x2
6047c478bd9Sstevel@tonic-gate	movl	%esi, 16(%esp)	/, dt
6057c478bd9Sstevel@tonic-gate	movb	%al, %cl
6067c478bd9Sstevel@tonic-gate	movl	32(%esp), %esi	/ x, dt
6077c478bd9Sstevel@tonic-gate	movl	%edi, 12(%esp)
6087c478bd9Sstevel@tonic-gate	movl	36(%esp), %edi	/ x, dt
6097c478bd9Sstevel@tonic-gate	shldl	%esi, %edi	/, dt, dt
6107c478bd9Sstevel@tonic-gate	sall	%cl, %esi	/, dt
6117c478bd9Sstevel@tonic-gate	andl	$32, %ecx
6127c478bd9Sstevel@tonic-gate	movl	%edx, 8(%esp)
6137c478bd9Sstevel@tonic-gate	je	.LL41
6147c478bd9Sstevel@tonic-gate	movl	%esi, %edi	/ dt, dt
6157c478bd9Sstevel@tonic-gate	xorl	%esi, %esi	/ dt
6167c478bd9Sstevel@tonic-gate.LL41:
6177c478bd9Sstevel@tonic-gate	xorl	%ecx, %ecx
6187c478bd9Sstevel@tonic-gate	movl	%edi, %eax	/ tmp1,
6197c478bd9Sstevel@tonic-gate	movl	%ebp, %edx	/ x2,
6207c478bd9Sstevel@tonic-gate	divl	8(%esp)
6217c478bd9Sstevel@tonic-gate	movl	%edx, %ebp	/, x1
6227c478bd9Sstevel@tonic-gate	movl	%ecx, 4(%esp)
6237c478bd9Sstevel@tonic-gate	movl	%eax, %ecx	/, q0
6247c478bd9Sstevel@tonic-gate	movl	16(%esp), %eax	/ dt,
6257c478bd9Sstevel@tonic-gate	mull	%ecx	/ q0
6267c478bd9Sstevel@tonic-gate	cmpl	%ebp, %edx	/ x1, t1
6277c478bd9Sstevel@tonic-gate	movl	%edi, (%esp)
6287c478bd9Sstevel@tonic-gate	movl	%esi, %edi	/ dt, x0
6297c478bd9Sstevel@tonic-gate	ja	.LL38
6307c478bd9Sstevel@tonic-gate	je	.LL44
6317c478bd9Sstevel@tonic-gate.LL39:
6327c478bd9Sstevel@tonic-gate	movl	%ecx, %esi	/ q0, <result>
6337c478bd9Sstevel@tonic-gate.LL46:
6347c478bd9Sstevel@tonic-gate	xorl	%edi, %edi	/ <result>
6357c478bd9Sstevel@tonic-gate	jmp	.LL45
6367c478bd9Sstevel@tonic-gate.LL44:
6377c478bd9Sstevel@tonic-gate	cmpl	%edi, %eax	/ x0, t0
6387c478bd9Sstevel@tonic-gate	jbe	.LL39
6397c478bd9Sstevel@tonic-gate.LL38:
6407c478bd9Sstevel@tonic-gate	decl	%ecx		/ q0
6417c478bd9Sstevel@tonic-gate	movl	%ecx, %esi	/ q0, <result>
6427c478bd9Sstevel@tonic-gate	jmp	.LL46
6437c478bd9Sstevel@tonic-gate.LL43:
6447c478bd9Sstevel@tonic-gate	movl	%esi, %edi
6457c478bd9Sstevel@tonic-gate	xorl	%esi, %esi
6467c478bd9Sstevel@tonic-gate	jmp	.LL40
6477c478bd9Sstevel@tonic-gate	SET_SIZE(UDiv)
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate/*
6507c478bd9Sstevel@tonic-gate * __udiv64
6517c478bd9Sstevel@tonic-gate *
6527c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the
6537c478bd9Sstevel@tonic-gate * quotient in %edx:%eax.  __udiv64 pops the arguments on return,
6547c478bd9Sstevel@tonic-gate */
6557c478bd9Sstevel@tonic-gate	ENTRY(__udiv64)
6567c478bd9Sstevel@tonic-gate	movl	4(%esp), %eax	/ x, x
6577c478bd9Sstevel@tonic-gate	movl	8(%esp), %edx	/ x, x
6587c478bd9Sstevel@tonic-gate	pushl	16(%esp)	/ y
6597c478bd9Sstevel@tonic-gate	pushl	16(%esp)
6607c478bd9Sstevel@tonic-gate	call	UDiv
6617c478bd9Sstevel@tonic-gate	addl	$8, %esp
6627c478bd9Sstevel@tonic-gate	ret     $16
6637c478bd9Sstevel@tonic-gate	SET_SIZE(__udiv64)
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate/*
6667c478bd9Sstevel@tonic-gate * __urem64
6677c478bd9Sstevel@tonic-gate *
6687c478bd9Sstevel@tonic-gate * Perform division of two unsigned 64-bit quantities, returning the
6697c478bd9Sstevel@tonic-gate * remainder in %edx:%eax.  __urem64 pops the arguments on return
6707c478bd9Sstevel@tonic-gate */
6717c478bd9Sstevel@tonic-gate	ENTRY(__urem64)
6727c478bd9Sstevel@tonic-gate	subl	$12, %esp
6737c478bd9Sstevel@tonic-gate	movl	%esp, %ecx	/, tmp65
6747c478bd9Sstevel@tonic-gate	movl	16(%esp), %eax	/ x, x
6757c478bd9Sstevel@tonic-gate	movl	20(%esp), %edx	/ x, x
6767c478bd9Sstevel@tonic-gate	pushl	%ecx		/ tmp65
6777c478bd9Sstevel@tonic-gate	pushl	32(%esp)	/ y
6787c478bd9Sstevel@tonic-gate	pushl	32(%esp)
6797c478bd9Sstevel@tonic-gate	call	UDivRem
6807c478bd9Sstevel@tonic-gate	movl	12(%esp), %eax	/ rem, rem
6817c478bd9Sstevel@tonic-gate	movl	16(%esp), %edx	/ rem, rem
6827c478bd9Sstevel@tonic-gate	addl	$24, %esp
6837c478bd9Sstevel@tonic-gate	ret	$16
6847c478bd9Sstevel@tonic-gate	SET_SIZE(__urem64)
6857c478bd9Sstevel@tonic-gate
6867c478bd9Sstevel@tonic-gate/*
6877c478bd9Sstevel@tonic-gate * __div64
6887c478bd9Sstevel@tonic-gate *
6897c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the
6907c478bd9Sstevel@tonic-gate * quotient in %edx:%eax.  __div64 pops the arguments on return.
6917c478bd9Sstevel@tonic-gate */
6927c478bd9Sstevel@tonic-gate/ int64_t
6937c478bd9Sstevel@tonic-gate/ __div64(int64_t x, int64_t y)
6947c478bd9Sstevel@tonic-gate/ {
6957c478bd9Sstevel@tonic-gate/ 	int		negative;
6967c478bd9Sstevel@tonic-gate/ 	uint64_t	xt, yt, r;
697*55fea89dSDan Cross/
6987c478bd9Sstevel@tonic-gate/ 	if (x < 0) {
6997c478bd9Sstevel@tonic-gate/ 		xt = -(uint64_t) x;
7007c478bd9Sstevel@tonic-gate/ 		negative = 1;
7017c478bd9Sstevel@tonic-gate/ 	} else {
7027c478bd9Sstevel@tonic-gate/ 		xt = x;
7037c478bd9Sstevel@tonic-gate/ 		negative = 0;
7047c478bd9Sstevel@tonic-gate/ 	}
7057c478bd9Sstevel@tonic-gate/ 	if (y < 0) {
7067c478bd9Sstevel@tonic-gate/ 		yt = -(uint64_t) y;
7077c478bd9Sstevel@tonic-gate/ 		negative ^= 1;
7087c478bd9Sstevel@tonic-gate/ 	} else {
7097c478bd9Sstevel@tonic-gate/ 		yt = y;
7107c478bd9Sstevel@tonic-gate/ 	}
7117c478bd9Sstevel@tonic-gate/ 	r = UDiv(xt, yt);
7127c478bd9Sstevel@tonic-gate/ 	return (negative ? (int64_t) - r : r);
7137c478bd9Sstevel@tonic-gate/ }
7147c478bd9Sstevel@tonic-gate	ENTRY(__div64)
7157c478bd9Sstevel@tonic-gate	pushl	%ebp
7167c478bd9Sstevel@tonic-gate	pushl	%edi
7177c478bd9Sstevel@tonic-gate	pushl	%esi
7187c478bd9Sstevel@tonic-gate	subl	$8, %esp
7197c478bd9Sstevel@tonic-gate	movl	28(%esp), %edx	/ x, x
7207c478bd9Sstevel@tonic-gate	testl	%edx, %edx	/ x
7217c478bd9Sstevel@tonic-gate	movl	24(%esp), %eax	/ x, x
7227c478bd9Sstevel@tonic-gate	movl	32(%esp), %esi	/ y, y
7237c478bd9Sstevel@tonic-gate	movl	36(%esp), %edi	/ y, y
7247c478bd9Sstevel@tonic-gate	js	.LL84
7257c478bd9Sstevel@tonic-gate	xorl	%ebp, %ebp	/ negative
7267c478bd9Sstevel@tonic-gate	testl	%edi, %edi	/ y
7277c478bd9Sstevel@tonic-gate	movl	%eax, (%esp)	/ x, xt
7287c478bd9Sstevel@tonic-gate	movl	%edx, 4(%esp)	/ x, xt
7297c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ y, yt
7307c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ y, yt
7317c478bd9Sstevel@tonic-gate	js	.LL85
7327c478bd9Sstevel@tonic-gate.LL82:
7337c478bd9Sstevel@tonic-gate	pushl	%edx		/ yt
7347c478bd9Sstevel@tonic-gate	pushl	%eax		/ yt
7357c478bd9Sstevel@tonic-gate	movl	8(%esp), %eax	/ xt, xt
7367c478bd9Sstevel@tonic-gate	movl	12(%esp), %edx	/ xt, xt
7377c478bd9Sstevel@tonic-gate	call	UDiv
7387c478bd9Sstevel@tonic-gate	popl	%ecx
7397c478bd9Sstevel@tonic-gate	testl	%ebp, %ebp	/ negative
7407c478bd9Sstevel@tonic-gate	popl	%esi
7417c478bd9Sstevel@tonic-gate	je	.LL83
7427c478bd9Sstevel@tonic-gate	negl	%eax		/ r
7437c478bd9Sstevel@tonic-gate	adcl	$0, %edx	/, r
7447c478bd9Sstevel@tonic-gate	negl	%edx		/ r
7457c478bd9Sstevel@tonic-gate.LL83:
7467c478bd9Sstevel@tonic-gate	addl	$8, %esp
7477c478bd9Sstevel@tonic-gate	popl	%esi
7487c478bd9Sstevel@tonic-gate	popl	%edi
7497c478bd9Sstevel@tonic-gate	popl	%ebp
7507c478bd9Sstevel@tonic-gate	ret	$16
7517c478bd9Sstevel@tonic-gate	.align	16
7527c478bd9Sstevel@tonic-gate.LL84:
7537c478bd9Sstevel@tonic-gate	negl	%eax		/ x
7547c478bd9Sstevel@tonic-gate	adcl	$0, %edx	/, x
7557c478bd9Sstevel@tonic-gate	negl	%edx		/ x
7567c478bd9Sstevel@tonic-gate	testl	%edi, %edi	/ y
7577c478bd9Sstevel@tonic-gate	movl	%eax, (%esp)	/ x, xt
7587c478bd9Sstevel@tonic-gate	movl	%edx, 4(%esp)	/ x, xt
7597c478bd9Sstevel@tonic-gate	movl	$1, %ebp	/, negative
7607c478bd9Sstevel@tonic-gate	movl	%esi, %eax	/ y, yt
7617c478bd9Sstevel@tonic-gate	movl	%edi, %edx	/ y, yt
7627c478bd9Sstevel@tonic-gate	jns	.LL82
7637c478bd9Sstevel@tonic-gate	.align	16
7647c478bd9Sstevel@tonic-gate.LL85:
7657c478bd9Sstevel@tonic-gate	negl	%eax		/ yt
7667c478bd9Sstevel@tonic-gate	adcl	$0, %edx	/, yt
7677c478bd9Sstevel@tonic-gate	negl	%edx		/ yt
7687c478bd9Sstevel@tonic-gate	xorl	$1, %ebp	/, negative
7697c478bd9Sstevel@tonic-gate	jmp	.LL82
7707c478bd9Sstevel@tonic-gate	SET_SIZE(__div64)
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate/*
7737c478bd9Sstevel@tonic-gate * __rem64
7747c478bd9Sstevel@tonic-gate *
7757c478bd9Sstevel@tonic-gate * Perform division of two signed 64-bit quantities, returning the
7767c478bd9Sstevel@tonic-gate * remainder in %edx:%eax.  __rem64 pops the arguments on return.
7777c478bd9Sstevel@tonic-gate */
7787c478bd9Sstevel@tonic-gate/ int64_t
7797c478bd9Sstevel@tonic-gate/ __rem64(int64_t x, int64_t y)
7807c478bd9Sstevel@tonic-gate/ {
7817c478bd9Sstevel@tonic-gate/ 	uint64_t	xt, yt, rem;
782*55fea89dSDan Cross/
7837c478bd9Sstevel@tonic-gate/ 	if (x < 0) {
7847c478bd9Sstevel@tonic-gate/ 		xt = -(uint64_t) x;
7857c478bd9Sstevel@tonic-gate/ 	} else {
7867c478bd9Sstevel@tonic-gate/ 		xt = x;
7877c478bd9Sstevel@tonic-gate/ 	}
7887c478bd9Sstevel@tonic-gate/ 	if (y < 0) {
7897c478bd9Sstevel@tonic-gate/ 		yt = -(uint64_t) y;
7907c478bd9Sstevel@tonic-gate/ 	} else {
7917c478bd9Sstevel@tonic-gate/ 		yt = y;
7927c478bd9Sstevel@tonic-gate/ 	}
7937c478bd9Sstevel@tonic-gate/ 	(void) UDivRem(xt, yt, &rem);
7947c478bd9Sstevel@tonic-gate/ 	return (x < 0 ? (int64_t) - rem : rem);
7957c478bd9Sstevel@tonic-gate/ }
7967c478bd9Sstevel@tonic-gate	ENTRY(__rem64)
7977c478bd9Sstevel@tonic-gate	pushl	%edi
7987c478bd9Sstevel@tonic-gate	pushl	%esi
7997c478bd9Sstevel@tonic-gate	subl	$20, %esp
8007c478bd9Sstevel@tonic-gate	movl	36(%esp), %ecx	/ x,
8017c478bd9Sstevel@tonic-gate	movl	32(%esp), %esi	/ x,
8027c478bd9Sstevel@tonic-gate	movl	36(%esp), %edi	/ x,
8037c478bd9Sstevel@tonic-gate	testl	%ecx, %ecx
8047c478bd9Sstevel@tonic-gate	movl	40(%esp), %eax	/ y, y
8057c478bd9Sstevel@tonic-gate	movl	44(%esp), %edx	/ y, y
8067c478bd9Sstevel@tonic-gate	movl	%esi, (%esp)	/, xt
8077c478bd9Sstevel@tonic-gate	movl	%edi, 4(%esp)	/, xt
8087c478bd9Sstevel@tonic-gate	js	.LL92
8097c478bd9Sstevel@tonic-gate	testl	%edx, %edx	/ y
8107c478bd9Sstevel@tonic-gate	movl	%eax, %esi	/ y, yt
8117c478bd9Sstevel@tonic-gate	movl	%edx, %edi	/ y, yt
8127c478bd9Sstevel@tonic-gate	js	.LL93
8137c478bd9Sstevel@tonic-gate.LL90:
8147c478bd9Sstevel@tonic-gate	leal	8(%esp), %eax	/, tmp66
8157c478bd9Sstevel@tonic-gate	pushl	%eax		/ tmp66
8167c478bd9Sstevel@tonic-gate	pushl	%edi		/ yt
8177c478bd9Sstevel@tonic-gate	pushl	%esi		/ yt
8187c478bd9Sstevel@tonic-gate	movl	12(%esp), %eax	/ xt, xt
8197c478bd9Sstevel@tonic-gate	movl	16(%esp), %edx	/ xt, xt
8207c478bd9Sstevel@tonic-gate	call	UDivRem
8217c478bd9Sstevel@tonic-gate	addl	$12, %esp
8227c478bd9Sstevel@tonic-gate	movl	36(%esp), %edi	/ x,
8237c478bd9Sstevel@tonic-gate	testl	%edi, %edi
8247c478bd9Sstevel@tonic-gate	movl	8(%esp), %eax	/ rem, rem
8257c478bd9Sstevel@tonic-gate	movl	12(%esp), %edx	/ rem, rem
8267c478bd9Sstevel@tonic-gate	js	.LL94
8277c478bd9Sstevel@tonic-gate	addl	$20, %esp
8287c478bd9Sstevel@tonic-gate	popl	%esi
8297c478bd9Sstevel@tonic-gate	popl	%edi
8307c478bd9Sstevel@tonic-gate	ret	$16
8317c478bd9Sstevel@tonic-gate	.align	16
8327c478bd9Sstevel@tonic-gate.LL92:
8337c478bd9Sstevel@tonic-gate	negl	%esi
8347c478bd9Sstevel@tonic-gate	adcl	$0, %edi
8357c478bd9Sstevel@tonic-gate	negl	%edi
8367c478bd9Sstevel@tonic-gate	testl	%edx, %edx	/ y
8377c478bd9Sstevel@tonic-gate	movl	%esi, (%esp)	/, xt
8387c478bd9Sstevel@tonic-gate	movl	%edi, 4(%esp)	/, xt
8397c478bd9Sstevel@tonic-gate	movl	%eax, %esi	/ y, yt
8407c478bd9Sstevel@tonic-gate	movl	%edx, %edi	/ y, yt
8417c478bd9Sstevel@tonic-gate	jns	.LL90
8427c478bd9Sstevel@tonic-gate	.align	16
8437c478bd9Sstevel@tonic-gate.LL93:
8447c478bd9Sstevel@tonic-gate	negl	%esi		/ yt
8457c478bd9Sstevel@tonic-gate	adcl	$0, %edi	/, yt
8467c478bd9Sstevel@tonic-gate	negl	%edi		/ yt
8477c478bd9Sstevel@tonic-gate	jmp	.LL90
8487c478bd9Sstevel@tonic-gate	.align	16
8497c478bd9Sstevel@tonic-gate.LL94:
8507c478bd9Sstevel@tonic-gate	negl	%eax		/ rem
8517c478bd9Sstevel@tonic-gate	adcl	$0, %edx	/, rem
8527c478bd9Sstevel@tonic-gate	addl	$20, %esp
8537c478bd9Sstevel@tonic-gate	popl	%esi
8547c478bd9Sstevel@tonic-gate	negl	%edx		/ rem
8557c478bd9Sstevel@tonic-gate	popl	%edi
8567c478bd9Sstevel@tonic-gate	ret	$16
8577c478bd9Sstevel@tonic-gate	SET_SIZE(__rem64)
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate#endif	/* __lint */
86089518a1cSdmick
86189518a1cSdmick#if defined(__lint)
86289518a1cSdmick
86389518a1cSdmick/*
86489518a1cSdmick * C support for 64-bit modulo and division.
865*55fea89dSDan Cross * GNU routines callable from C (though generated by the compiler).
86689518a1cSdmick * Hand-customized compiler output - see comments for details.
86789518a1cSdmick */
86889518a1cSdmick/*ARGSUSED*/
86989518a1cSdmickunsigned long long
87089518a1cSdmick__udivdi3(unsigned long long a, unsigned long long b)
87189518a1cSdmick{ return (0); }
87289518a1cSdmick
87389518a1cSdmick/*ARGSUSED*/
87489518a1cSdmickunsigned long long
87589518a1cSdmick__umoddi3(unsigned long long a, unsigned long long b)
87689518a1cSdmick{ return (0); }
87789518a1cSdmick
87889518a1cSdmick/*ARGSUSED*/
87989518a1cSdmicklong long
88089518a1cSdmick__divdi3(long long a, long long b)
88189518a1cSdmick{ return (0); }
88289518a1cSdmick
88389518a1cSdmick/*ARGSUSED*/
88489518a1cSdmicklong long
88589518a1cSdmick__moddi3(long long a, long long b)
88689518a1cSdmick{ return (0); }
88789518a1cSdmick
88889518a1cSdmick/* ARGSUSED */
88989518a1cSdmickint64_t __divrem64(int64_t a, int64_t b)
89089518a1cSdmick{ return (0); }
89189518a1cSdmick
89289518a1cSdmick/* ARGSUSED */
89389518a1cSdmickuint64_t __udivrem64(uint64_t a, uint64_t b)
89489518a1cSdmick{ return (0); }
89589518a1cSdmick
89689518a1cSdmick#else	/* __lint */
89789518a1cSdmick
89889518a1cSdmick/*
89989518a1cSdmick * int32_t/int64_t division/manipulation
90089518a1cSdmick *
90189518a1cSdmick * Hand-customized compiler output: the non-GCC entry points depart from
90289518a1cSdmick * the SYS V ABI by requiring their arguments to be popped, and in the
90389518a1cSdmick * [u]divrem64 cases returning the remainder in %ecx:%esi. Note the
90489518a1cSdmick * compiler-generated use of %edx:%eax for the first argument of
90589518a1cSdmick * internal entry points.
90689518a1cSdmick *
90789518a1cSdmick * Inlines for speed:
90889518a1cSdmick * - counting the number of leading zeros in a word
90989518a1cSdmick * - multiplying two 32-bit numbers giving a 64-bit result
91089518a1cSdmick * - dividing a 64-bit number by a 32-bit number, giving both quotient
91189518a1cSdmick *	and remainder
91289518a1cSdmick * - subtracting two 64-bit results
91389518a1cSdmick */
91489518a1cSdmick/ #define	LO(X)		((uint32_t)(X) & 0xffffffff)
91589518a1cSdmick/ #define	HI(X)		((uint32_t)((X) >> 32) & 0xffffffff)
91689518a1cSdmick/ #define	HILO(H, L)	(((uint64_t)(H) << 32) + (L))
917*55fea89dSDan Cross/
91889518a1cSdmick/ /* give index of highest bit */
91989518a1cSdmick/ #define	HIBIT(a, r) \
92089518a1cSdmick/     asm("bsrl %1,%0": "=r"((uint32_t)(r)) : "g" (a))
921*55fea89dSDan Cross/
92289518a1cSdmick/ /* multiply two uint32_ts resulting in a uint64_t */
92389518a1cSdmick/ #define	A_MUL32(a, b, lo, hi) \
92489518a1cSdmick/     asm("mull %2" \
92589518a1cSdmick/ 	: "=a"((uint32_t)(lo)), "=d"((uint32_t)(hi)) : "g" (b), "0"(a))
926*55fea89dSDan Cross/
92789518a1cSdmick/ /* divide a uint64_t by a uint32_t */
92889518a1cSdmick/ #define	A_DIV32(lo, hi, b, q, r) \
92989518a1cSdmick/     asm("divl %2" \
93089518a1cSdmick/ 	: "=a"((uint32_t)(q)), "=d"((uint32_t)(r)) \
93189518a1cSdmick/ 	: "g" (b), "0"((uint32_t)(lo)), "1"((uint32_t)hi))
932*55fea89dSDan Cross/
93389518a1cSdmick/ /* subtract two uint64_ts (with borrow) */
93489518a1cSdmick/ #define	A_SUB2(bl, bh, al, ah) \
93589518a1cSdmick/     asm("subl %4,%0\n\tsbbl %5,%1" \
93689518a1cSdmick/ 	: "=&r"((uint32_t)(al)), "=r"((uint32_t)(ah)) \
93789518a1cSdmick/ 	: "0"((uint32_t)(al)), "1"((uint32_t)(ah)), "g"((uint32_t)(bl)), \
93889518a1cSdmick/ 	"g"((uint32_t)(bh)))
93989518a1cSdmick
94089518a1cSdmick/*
94189518a1cSdmick * __udivdi3
94289518a1cSdmick *
94389518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the
94489518a1cSdmick * quotient in %edx:%eax.
94589518a1cSdmick */
94689518a1cSdmick	ENTRY(__udivdi3)
94789518a1cSdmick	movl	4(%esp), %eax	/ x, x
94889518a1cSdmick	movl	8(%esp), %edx	/ x, x
94989518a1cSdmick	pushl	16(%esp)	/ y
95089518a1cSdmick	pushl	16(%esp)
95189518a1cSdmick	call	UDiv
95289518a1cSdmick	addl	$8, %esp
95389518a1cSdmick	ret
95489518a1cSdmick	SET_SIZE(__udivdi3)
95589518a1cSdmick
95689518a1cSdmick/*
95789518a1cSdmick * __umoddi3
95889518a1cSdmick *
95989518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the
96089518a1cSdmick * remainder in %edx:%eax.
96189518a1cSdmick */
96289518a1cSdmick	ENTRY(__umoddi3)
96389518a1cSdmick	subl	$12, %esp
96489518a1cSdmick	movl	%esp, %ecx	/, tmp65
96589518a1cSdmick	movl	16(%esp), %eax	/ x, x
96689518a1cSdmick	movl	20(%esp), %edx	/ x, x
96789518a1cSdmick	pushl	%ecx		/ tmp65
96889518a1cSdmick	pushl	32(%esp)	/ y
96989518a1cSdmick	pushl	32(%esp)
97089518a1cSdmick	call	UDivRem
97189518a1cSdmick	movl	12(%esp), %eax	/ rem, rem
97289518a1cSdmick	movl	16(%esp), %edx	/ rem, rem
97389518a1cSdmick	addl	$24, %esp
97489518a1cSdmick	ret
97589518a1cSdmick	SET_SIZE(__umoddi3)
97689518a1cSdmick
97789518a1cSdmick/*
97889518a1cSdmick * __divdi3
97989518a1cSdmick *
98089518a1cSdmick * Perform division of two signed 64-bit quantities, returning the
98189518a1cSdmick * quotient in %edx:%eax.
98289518a1cSdmick */
98389518a1cSdmick/ int64_t
98489518a1cSdmick/ __divdi3(int64_t x, int64_t y)
98589518a1cSdmick/ {
98689518a1cSdmick/ 	int		negative;
98789518a1cSdmick/ 	uint64_t	xt, yt, r;
988*55fea89dSDan Cross/
98989518a1cSdmick/ 	if (x < 0) {
99089518a1cSdmick/ 		xt = -(uint64_t) x;
99189518a1cSdmick/ 		negative = 1;
99289518a1cSdmick/ 	} else {
99389518a1cSdmick/ 		xt = x;
99489518a1cSdmick/ 		negative = 0;
99589518a1cSdmick/ 	}
99689518a1cSdmick/ 	if (y < 0) {
99789518a1cSdmick/ 		yt = -(uint64_t) y;
99889518a1cSdmick/ 		negative ^= 1;
99989518a1cSdmick/ 	} else {
100089518a1cSdmick/ 		yt = y;
100189518a1cSdmick/ 	}
100289518a1cSdmick/ 	r = UDiv(xt, yt);
100389518a1cSdmick/ 	return (negative ? (int64_t) - r : r);
100489518a1cSdmick/ }
100589518a1cSdmick	ENTRY(__divdi3)
100689518a1cSdmick	pushl	%ebp
100789518a1cSdmick	pushl	%edi
100889518a1cSdmick	pushl	%esi
100989518a1cSdmick	subl	$8, %esp
101089518a1cSdmick	movl	28(%esp), %edx	/ x, x
101189518a1cSdmick	testl	%edx, %edx	/ x
101289518a1cSdmick	movl	24(%esp), %eax	/ x, x
101389518a1cSdmick	movl	32(%esp), %esi	/ y, y
101489518a1cSdmick	movl	36(%esp), %edi	/ y, y
101589518a1cSdmick	js	.LL55
101689518a1cSdmick	xorl	%ebp, %ebp	/ negative
101789518a1cSdmick	testl	%edi, %edi	/ y
101889518a1cSdmick	movl	%eax, (%esp)	/ x, xt
101989518a1cSdmick	movl	%edx, 4(%esp)	/ x, xt
102089518a1cSdmick	movl	%esi, %eax	/ y, yt
102189518a1cSdmick	movl	%edi, %edx	/ y, yt
102289518a1cSdmick	js	.LL56
102389518a1cSdmick.LL53:
102489518a1cSdmick	pushl	%edx		/ yt
102589518a1cSdmick	pushl	%eax		/ yt
102689518a1cSdmick	movl	8(%esp), %eax	/ xt, xt
102789518a1cSdmick	movl	12(%esp), %edx	/ xt, xt
102889518a1cSdmick	call	UDiv
102989518a1cSdmick	popl	%ecx
103089518a1cSdmick	testl	%ebp, %ebp	/ negative
103189518a1cSdmick	popl	%esi
103289518a1cSdmick	je	.LL54
103389518a1cSdmick	negl	%eax		/ r
103489518a1cSdmick	adcl	$0, %edx	/, r
103589518a1cSdmick	negl	%edx		/ r
103689518a1cSdmick.LL54:
103789518a1cSdmick	addl	$8, %esp
103889518a1cSdmick	popl	%esi
103989518a1cSdmick	popl	%edi
104089518a1cSdmick	popl	%ebp
104189518a1cSdmick	ret
104289518a1cSdmick	.align	16
104389518a1cSdmick.LL55:
104489518a1cSdmick	negl	%eax		/ x
104589518a1cSdmick	adcl	$0, %edx	/, x
104689518a1cSdmick	negl	%edx		/ x
104789518a1cSdmick	testl	%edi, %edi	/ y
104889518a1cSdmick	movl	%eax, (%esp)	/ x, xt
104989518a1cSdmick	movl	%edx, 4(%esp)	/ x, xt
105089518a1cSdmick	movl	$1, %ebp	/, negative
105189518a1cSdmick	movl	%esi, %eax	/ y, yt
105289518a1cSdmick	movl	%edi, %edx	/ y, yt
105389518a1cSdmick	jns	.LL53
105489518a1cSdmick	.align	16
105589518a1cSdmick.LL56:
105689518a1cSdmick	negl	%eax		/ yt
105789518a1cSdmick	adcl	$0, %edx	/, yt
105889518a1cSdmick	negl	%edx		/ yt
105989518a1cSdmick	xorl	$1, %ebp	/, negative
106089518a1cSdmick	jmp	.LL53
106189518a1cSdmick	SET_SIZE(__divdi3)
106289518a1cSdmick
106389518a1cSdmick/*
106489518a1cSdmick * __moddi3
106589518a1cSdmick *
106689518a1cSdmick * Perform division of two signed 64-bit quantities, returning the
106789518a1cSdmick * quotient in %edx:%eax.
106889518a1cSdmick */
106989518a1cSdmick/ int64_t
107089518a1cSdmick/ __moddi3(int64_t x, int64_t y)
107189518a1cSdmick/ {
107289518a1cSdmick/ 	uint64_t	xt, yt, rem;
1073*55fea89dSDan Cross/
107489518a1cSdmick/ 	if (x < 0) {
107589518a1cSdmick/ 		xt = -(uint64_t) x;
107689518a1cSdmick/ 	} else {
107789518a1cSdmick/ 		xt = x;
107889518a1cSdmick/ 	}
107989518a1cSdmick/ 	if (y < 0) {
108089518a1cSdmick/ 		yt = -(uint64_t) y;
108189518a1cSdmick/ 	} else {
108289518a1cSdmick/ 		yt = y;
108389518a1cSdmick/ 	}
108489518a1cSdmick/ 	(void) UDivRem(xt, yt, &rem);
108589518a1cSdmick/ 	return (x < 0 ? (int64_t) - rem : rem);
108689518a1cSdmick/ }
108789518a1cSdmick	ENTRY(__moddi3)
108889518a1cSdmick	pushl	%edi
108989518a1cSdmick	pushl	%esi
109089518a1cSdmick	subl	$20, %esp
109189518a1cSdmick	movl	36(%esp), %ecx	/ x,
109289518a1cSdmick	movl	32(%esp), %esi	/ x,
109389518a1cSdmick	movl	36(%esp), %edi	/ x,
109489518a1cSdmick	testl	%ecx, %ecx
109589518a1cSdmick	movl	40(%esp), %eax	/ y, y
109689518a1cSdmick	movl	44(%esp), %edx	/ y, y
109789518a1cSdmick	movl	%esi, (%esp)	/, xt
109889518a1cSdmick	movl	%edi, 4(%esp)	/, xt
109989518a1cSdmick	js	.LL63
110089518a1cSdmick	testl	%edx, %edx	/ y
110189518a1cSdmick	movl	%eax, %esi	/ y, yt
110289518a1cSdmick	movl	%edx, %edi	/ y, yt
110389518a1cSdmick	js	.LL64
110489518a1cSdmick.LL61:
110589518a1cSdmick	leal	8(%esp), %eax	/, tmp66
110689518a1cSdmick	pushl	%eax		/ tmp66
110789518a1cSdmick	pushl	%edi		/ yt
110889518a1cSdmick	pushl	%esi		/ yt
110989518a1cSdmick	movl	12(%esp), %eax	/ xt, xt
111089518a1cSdmick	movl	16(%esp), %edx	/ xt, xt
111189518a1cSdmick	call	UDivRem
111289518a1cSdmick	addl	$12, %esp
111389518a1cSdmick	movl	36(%esp), %edi	/ x,
111489518a1cSdmick	testl	%edi, %edi
111589518a1cSdmick	movl	8(%esp), %eax	/ rem, rem
111689518a1cSdmick	movl	12(%esp), %edx	/ rem, rem
111789518a1cSdmick	js	.LL65
111889518a1cSdmick	addl	$20, %esp
111989518a1cSdmick	popl	%esi
112089518a1cSdmick	popl	%edi
112189518a1cSdmick	ret
112289518a1cSdmick	.align	16
112389518a1cSdmick.LL63:
112489518a1cSdmick	negl	%esi
112589518a1cSdmick	adcl	$0, %edi
112689518a1cSdmick	negl	%edi
112789518a1cSdmick	testl	%edx, %edx	/ y
112889518a1cSdmick	movl	%esi, (%esp)	/, xt
112989518a1cSdmick	movl	%edi, 4(%esp)	/, xt
113089518a1cSdmick	movl	%eax, %esi	/ y, yt
113189518a1cSdmick	movl	%edx, %edi	/ y, yt
113289518a1cSdmick	jns	.LL61
113389518a1cSdmick	.align	16
113489518a1cSdmick.LL64:
113589518a1cSdmick	negl	%esi		/ yt
113689518a1cSdmick	adcl	$0, %edi	/, yt
113789518a1cSdmick	negl	%edi		/ yt
113889518a1cSdmick	jmp	.LL61
113989518a1cSdmick	.align	16
114089518a1cSdmick.LL65:
114189518a1cSdmick	negl	%eax		/ rem
114289518a1cSdmick	adcl	$0, %edx	/, rem
114389518a1cSdmick	addl	$20, %esp
114489518a1cSdmick	popl	%esi
114589518a1cSdmick	negl	%edx		/ rem
114689518a1cSdmick	popl	%edi
114789518a1cSdmick	ret
114889518a1cSdmick	SET_SIZE(__moddi3)
114989518a1cSdmick
115089518a1cSdmick/*
115189518a1cSdmick * __udivrem64
115289518a1cSdmick *
115389518a1cSdmick * Perform division of two unsigned 64-bit quantities, returning the
115489518a1cSdmick * quotient in %edx:%eax, and the remainder in %ecx:%esi.  __udivrem64
115589518a1cSdmick * pops the arguments on return.
115689518a1cSdmick */
115789518a1cSdmick	ENTRY(__udivrem64)
115889518a1cSdmick	subl	$12, %esp
115989518a1cSdmick	movl	%esp, %ecx	/, tmp64
116089518a1cSdmick	movl	16(%esp), %eax	/ x, x
116189518a1cSdmick	movl	20(%esp), %edx	/ x, x
116289518a1cSdmick	pushl	%ecx		/ tmp64
116389518a1cSdmick	pushl	32(%esp)	/ y
116489518a1cSdmick	pushl	32(%esp)
116589518a1cSdmick	call	UDivRem
116689518a1cSdmick	movl	16(%esp), %ecx	/ rem, tmp63
116789518a1cSdmick	movl	12(%esp), %esi	/ rem
116889518a1cSdmick	addl	$24, %esp
116989518a1cSdmick	ret	$16
117089518a1cSdmick	SET_SIZE(__udivrem64)
117189518a1cSdmick
117289518a1cSdmick/*
117389518a1cSdmick * Signed division with remainder.
117489518a1cSdmick */
117589518a1cSdmick/ int64_t
117689518a1cSdmick/ SDivRem(int64_t x, int64_t y, int64_t * pmod)
117789518a1cSdmick/ {
117889518a1cSdmick/ 	int		negative;
117989518a1cSdmick/ 	uint64_t	xt, yt, r, rem;
1180*55fea89dSDan Cross/
118189518a1cSdmick/ 	if (x < 0) {
118289518a1cSdmick/ 		xt = -(uint64_t) x;
118389518a1cSdmick/ 		negative = 1;
118489518a1cSdmick/ 	} else {
118589518a1cSdmick/ 		xt = x;
118689518a1cSdmick/ 		negative = 0;
118789518a1cSdmick/ 	}
118889518a1cSdmick/ 	if (y < 0) {
118989518a1cSdmick/ 		yt = -(uint64_t) y;
119089518a1cSdmick/ 		negative ^= 1;
119189518a1cSdmick/ 	} else {
119289518a1cSdmick/ 		yt = y;
119389518a1cSdmick/ 	}
119489518a1cSdmick/ 	r = UDivRem(xt, yt, &rem);
119589518a1cSdmick/ 	*pmod = (x < 0 ? (int64_t) - rem : rem);
119689518a1cSdmick/ 	return (negative ? (int64_t) - r : r);
119789518a1cSdmick/ }
119889518a1cSdmick	ENTRY(SDivRem)
119989518a1cSdmick	pushl	%ebp
120089518a1cSdmick	pushl	%edi
120189518a1cSdmick	pushl	%esi
120289518a1cSdmick	subl	$24, %esp
120389518a1cSdmick	testl	%edx, %edx	/ x
120489518a1cSdmick	movl	%edx, %edi	/ x, x
120589518a1cSdmick	js	.LL73
120689518a1cSdmick	movl	44(%esp), %esi	/ y,
120789518a1cSdmick	xorl	%ebp, %ebp	/ negative
120889518a1cSdmick	testl	%esi, %esi
120989518a1cSdmick	movl	%edx, 12(%esp)	/ x, xt
121089518a1cSdmick	movl	%eax, 8(%esp)	/ x, xt
121189518a1cSdmick	movl	40(%esp), %edx	/ y, yt
121289518a1cSdmick	movl	44(%esp), %ecx	/ y, yt
121389518a1cSdmick	js	.LL74
121489518a1cSdmick.LL70:
121589518a1cSdmick	leal	16(%esp), %eax	/, tmp70
121689518a1cSdmick	pushl	%eax		/ tmp70
121789518a1cSdmick	pushl	%ecx		/ yt
121889518a1cSdmick	pushl	%edx		/ yt
121989518a1cSdmick	movl	20(%esp), %eax	/ xt, xt
122089518a1cSdmick	movl	24(%esp), %edx	/ xt, xt
122189518a1cSdmick	call	UDivRem
122289518a1cSdmick	movl	%edx, 16(%esp)	/, r
122389518a1cSdmick	movl	%eax, 12(%esp)	/, r
122489518a1cSdmick	addl	$12, %esp
122589518a1cSdmick	testl	%edi, %edi	/ x
122689518a1cSdmick	movl	16(%esp), %edx	/ rem, rem
122789518a1cSdmick	movl	20(%esp), %ecx	/ rem, rem
122889518a1cSdmick	js	.LL75
122989518a1cSdmick.LL71:
123089518a1cSdmick	movl	48(%esp), %edi	/ pmod, pmod
123189518a1cSdmick	testl	%ebp, %ebp	/ negative
123289518a1cSdmick	movl	%edx, (%edi)	/ rem,* pmod
123389518a1cSdmick	movl	%ecx, 4(%edi)	/ rem,
123489518a1cSdmick	movl	(%esp), %eax	/ r, r
123589518a1cSdmick	movl	4(%esp), %edx	/ r, r
123689518a1cSdmick	je	.LL72
123789518a1cSdmick	negl	%eax		/ r
123889518a1cSdmick	adcl	$0, %edx	/, r
123989518a1cSdmick	negl	%edx		/ r
124089518a1cSdmick.LL72:
124189518a1cSdmick	addl	$24, %esp
124289518a1cSdmick	popl	%esi
124389518a1cSdmick	popl	%edi
124489518a1cSdmick	popl	%ebp
124589518a1cSdmick	ret
124689518a1cSdmick	.align	16
124789518a1cSdmick.LL73:
124889518a1cSdmick	negl	%eax
124989518a1cSdmick	adcl	$0, %edx
125089518a1cSdmick	movl	44(%esp), %esi	/ y,
125189518a1cSdmick	negl	%edx
125289518a1cSdmick	testl	%esi, %esi
125389518a1cSdmick	movl	%edx, 12(%esp)	/, xt
125489518a1cSdmick	movl	%eax, 8(%esp)	/, xt
125589518a1cSdmick	movl	$1, %ebp	/, negative
125689518a1cSdmick	movl	40(%esp), %edx	/ y, yt
125789518a1cSdmick	movl	44(%esp), %ecx	/ y, yt
125889518a1cSdmick	jns	.LL70
125989518a1cSdmick	.align	16
126089518a1cSdmick.LL74:
126189518a1cSdmick	negl	%edx		/ yt
126289518a1cSdmick	adcl	$0, %ecx	/, yt
126389518a1cSdmick	negl	%ecx		/ yt
126489518a1cSdmick	xorl	$1, %ebp	/, negative
126589518a1cSdmick	jmp	.LL70
126689518a1cSdmick	.align	16
126789518a1cSdmick.LL75:
126889518a1cSdmick	negl	%edx		/ rem
126989518a1cSdmick	adcl	$0, %ecx	/, rem
127089518a1cSdmick	negl	%ecx		/ rem
127189518a1cSdmick	jmp	.LL71
127289518a1cSdmick	SET_SIZE(SDivRem)
127389518a1cSdmick
127489518a1cSdmick/*
127589518a1cSdmick * __divrem64
127689518a1cSdmick *
127789518a1cSdmick * Perform division of two signed 64-bit quantities, returning the
127889518a1cSdmick * quotient in %edx:%eax, and the remainder in %ecx:%esi.  __divrem64
127989518a1cSdmick * pops the arguments on return.
128089518a1cSdmick */
128189518a1cSdmick	ENTRY(__divrem64)
128289518a1cSdmick	subl	$20, %esp
128389518a1cSdmick	movl	%esp, %ecx	/, tmp64
128489518a1cSdmick	movl	24(%esp), %eax	/ x, x
128589518a1cSdmick	movl	28(%esp), %edx	/ x, x
128689518a1cSdmick	pushl	%ecx		/ tmp64
128789518a1cSdmick	pushl	40(%esp)	/ y
128889518a1cSdmick	pushl	40(%esp)
128989518a1cSdmick	call	SDivRem
129089518a1cSdmick	movl	16(%esp), %ecx
129189518a1cSdmick	movl	12(%esp),%esi	/ rem
129289518a1cSdmick	addl	$32, %esp
129389518a1cSdmick	ret	$16
129489518a1cSdmick	SET_SIZE(__divrem64)
129589518a1cSdmick
129689518a1cSdmick
129789518a1cSdmick#endif /* __lint */
129889518a1cSdmick
129989518a1cSdmick#endif /* defined(__i386) && !defined(__amd64) */
1300