/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#if !defined(lint)
.ident "%Z%%M% %I% %E% SMI"
#endif
/*
* Helper routines for 32-bit compilers to perform 64-bit math.
* These are used both by the Sun and GCC compilers.
*/
#include <sys/asm_linkage.h>
#include <sys/asm_misc.h>
#if defined(__lint)
/* ARGSUSED */
{
return (0);
}
#else /* __lint */
/
/
/ a b parameter A
/ x c d parameter B
/ ---------
/ -----------------
/
/
ret $16
#endif /* __lint */
/*
* C support for 64-bit modulo and division.
* Hand-customized compiler output - see comments for details.
*/
#if defined(__lint)
/* ARGSUSED */
{ return (0); }
/* ARGSUSED */
{ return (0); }
/* ARGSUSED */
{ return (0); }
/* ARGSUSED */
{ return (0); }
#else /* __lint */
/ /*
/ * Unsigned division with remainder.
/ * Divide two uint64_ts, and calculate remainder.
/ */
/ uint64_t
/ {
/ /* simple cases: y is a single uint32_t */
/ if (HI(y) == 0) {
/
/ /* calculate q1 */
/ /* result is a single uint32_t, use one division */
/ q1 = 0;
/ } else {
/ /* result is a double uint32_t, use two divisions */
/ }
/
/ /* calculate q0 and remainder */
/
/ /* return remainder */
/
/ /* return result */
/
/ /* HI(x) < HI(y) => x < y => result is 0 */
/
/ /* return remainder */
/ *pmod = x;
/
/ /* return result */
/ return (0);
/
/ } else {
/ /*
/ * uint64_t by uint64_t division, resulting in a one-uint32_t
/ * result
/ */
/
/ /* normalize by shifting x and y so MSB(y) == 1 */
/
/ if (normshift == 0) {
/ /* no shifting needed, and x < 2*y so q <= 1 */
/
/ /* if x >= y then q = 1 (note x1 >= y1) */
/ q0 = 1;
/ /* subtract y from x to get remainder */
/ } else {
/ q0 = 0;
/ }
/
/ /* return remainder */
/
/ /* return result */
/ return (q0);
/
/ } else {
/ /*
/ * the last case: result is one uint32_t, but we need to
/ * normalize
/ */
/
/ /* normalize y */
/
/ /* normalize x (we need 3 uint32_ts!!!) */
/
/ /* estimate q0, and reduce x to a two uint32_t value */
/
/ /* adjust q0 down if too high */
/ /*
/ * because of the limited range of x2 we can only be
/ * one off
/ */
/ q0--;
/ }
/ /* return remainder */
/ /* subtract product from x to get remainder */
/
/ /* return result */
/ return (q0);
/ }
/ }
/ }
.LL4:
.align 16
.LL2:
.LL22:
.align 16
.LL21:
.align 16
.LL6:
.LL10:
.LL11:
.align 16
.LL8:
.LL17:
.LL18:
.LL15:
.LL16:
.align 16
.LL24:
.LL14:
.LL23:
/*
* Unsigned division without remainder.
*/
/ uint64_t
/ {
/ if (HI(y) == 0) {
/ /* simple cases: y is a single uint32_t */
/
/ /* calculate q1 */
/ /* result is a single uint32_t, use one division */
/ q1 = 0;
/ } else {
/ /* result is a double uint32_t, use two divisions */
/ }
/
/ /* calculate q0 and remainder */
/
/ /* return result */
/
/ /* HI(x) < HI(y) => x < y => result is 0 */
/
/ /* return result */
/ return (0);
/
/ } else {
/ /*
/ * uint64_t by uint64_t division, resulting in a one-uint32_t
/ * result
/ */
/ unsigned normshift;
/
/ /* normalize by shifting x and y so MSB(y) == 1 */
/
/ if (normshift == 0) {
/ /* no shifting needed, and x < 2*y so q <= 1 */
/
/ /* if x >= y then q = 1 (note x1 >= y1) */
/ q0 = 1;
/ /* subtract y from x to get remainder */
/ /* A_SUB2(y0, y1, x0, x1); */
/ } else {
/ q0 = 0;
/ }
/
/ /* return result */
/ return (q0);
/
/ } else {
/ /*
/ * the last case: result is one uint32_t, but we need to
/ * normalize
/ */
/
/ /* normalize y */
/
/ /* normalize x (we need 3 uint32_ts!!!) */
/
/ /* estimate q0, and reduce x to a two uint32_t value */
/
/ /* adjust q0 down if too high */
/ /*
/ * because of the limited range of x2 we can only be
/ * one off
/ */
/ q0--;
/ }
/ /* return result */
/ return (q0);
/ }
/ }
/ }
.LL28:
.LL25:
.align 16
.LL26:
.LL34:
.LL35:
.LL45:
.align 16
.LL32:
.LL40:
.LL41:
.LL39:
.LL46:
.LL44:
.LL38:
.LL43:
/*
* __udiv64
*
* Perform division of two unsigned 64-bit quantities, returning the
* quotient in %edx:%eax. __udiv64 pops the arguments on return,
*/
ret $16
/*
* __urem64
*
* Perform division of two unsigned 64-bit quantities, returning the
* remainder in %edx:%eax. __urem64 pops the arguments on return
*/
ret $16
/*
* __div64
*
* Perform division of two signed 64-bit quantities, returning the
* quotient in %edx:%eax. __div64 pops the arguments on return.
*/
/ int64_t
/ {
/ int negative;
/
/ if (x < 0) {
/ negative = 1;
/ } else {
/ xt = x;
/ negative = 0;
/ }
/ if (y < 0) {
/ negative ^= 1;
/ } else {
/ yt = y;
/ }
/ }
.LL82:
.LL83:
ret $16
.align 16
.LL84:
.align 16
.LL85:
/*
* __rem64
*
* Perform division of two signed 64-bit quantities, returning the
* remainder in %edx:%eax. __rem64 pops the arguments on return.
*/
/ int64_t
/ {
/
/ if (x < 0) {
/ } else {
/ xt = x;
/ }
/ if (y < 0) {
/ } else {
/ yt = y;
/ }
/ }
.LL90:
ret $16
.align 16
.LL92:
.align 16
.LL93:
.align 16
.LL94:
ret $16
#endif /* __lint */
#if defined(__lint)
/*
* C support for 64-bit modulo and division.
* GNU routines callable from C (though generated by the compiler).
* Hand-customized compiler output - see comments for details.
*/
/*ARGSUSED*/
unsigned long long
__udivdi3(unsigned long long a, unsigned long long b)
{ return (0); }
/*ARGSUSED*/
unsigned long long
__umoddi3(unsigned long long a, unsigned long long b)
{ return (0); }
/*ARGSUSED*/
long long
__divdi3(long long a, long long b)
{ return (0); }
/*ARGSUSED*/
long long
__moddi3(long long a, long long b)
{ return (0); }
/* ARGSUSED */
{ return (0); }
/* ARGSUSED */
{ return (0); }
#else /* __lint */
/*
*
* Hand-customized compiler output: the non-GCC entry points depart from
* the SYS V ABI by requiring their arguments to be popped, and in the
* [u]divrem64 cases returning the remainder in %ecx:%esi. Note the
* compiler-generated use of %edx:%eax for the first argument of
* internal entry points.
*
* Inlines for speed:
* - counting the number of leading zeros in a word
* - multiplying two 32-bit numbers giving a 64-bit result
* - dividing a 64-bit number by a 32-bit number, giving both quotient
* and remainder
* - subtracting two 64-bit results
*/
/
/ /* give index of highest bit */
/ #define HIBIT(a, r) \
/
/ /* multiply two uint32_ts resulting in a uint64_t */
/ asm("mull %2" \
/
/ /* divide a uint64_t by a uint32_t */
/ asm("divl %2" \
/
/ /* subtract two uint64_ts (with borrow) */
/ asm("subl %4,%0\n\tsbbl %5,%1" \
/*
* __udivdi3
*
* Perform division of two unsigned 64-bit quantities, returning the
* quotient in %edx:%eax.
*/
/*
* __umoddi3
*
* Perform division of two unsigned 64-bit quantities, returning the
* remainder in %edx:%eax.
*/
/*
* __divdi3
*
* Perform division of two signed 64-bit quantities, returning the
* quotient in %edx:%eax.
*/
/ int64_t
/ {
/ int negative;
/
/ if (x < 0) {
/ negative = 1;
/ } else {
/ xt = x;
/ negative = 0;
/ }
/ if (y < 0) {
/ negative ^= 1;
/ } else {
/ yt = y;
/ }
/ }
.LL53:
.LL54:
.align 16
.LL55:
.align 16
.LL56:
/*
* __moddi3
*
* Perform division of two signed 64-bit quantities, returning the
* quotient in %edx:%eax.
*/
/ int64_t
/ {
/
/ if (x < 0) {
/ } else {
/ xt = x;
/ }
/ if (y < 0) {
/ } else {
/ yt = y;
/ }
/ }
.LL61:
.align 16
.LL63:
.align 16
.LL64:
.align 16
.LL65:
/*
* __udivrem64
*
* Perform division of two unsigned 64-bit quantities, returning the
* quotient in %edx:%eax, and the remainder in %ecx:%esi. __udivrem64
* pops the arguments on return.
*/
ret $16
/*
* Signed division with remainder.
*/
/ int64_t
/ {
/ int negative;
/
/ if (x < 0) {
/ negative = 1;
/ } else {
/ xt = x;
/ negative = 0;
/ }
/ if (y < 0) {
/ negative ^= 1;
/ } else {
/ yt = y;
/ }
/ }
.LL70:
.LL71:
.LL72:
.align 16
.LL73:
.align 16
.LL74:
.align 16
.LL75:
/*
* __divrem64
*
* Perform division of two signed 64-bit quantities, returning the
* quotient in %edx:%eax, and the remainder in %ecx:%esi. __divrem64
* pops the arguments on return.
*/
ret $16
#endif /* __lint */
#endif /* defined(__i386) && !defined(__amd64) */