/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* 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 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "libm.h"
#include "fma.h"
#include "fenv_inlines.h"
#if defined(__sparc)
static const union {
unsigned i[2];
double d;
} C[] = {
{ 0x3fe00000u, 0 },
{ 0x40000000u, 0 },
{ 0x3ef00000u, 0 },
{ 0x3e700000u, 0 },
{ 0x41300000u, 0 },
{ 0x3e300000u, 0 },
{ 0x3b300000u, 0 },
{ 0x38300000u, 0 },
{ 0x42300000u, 0 },
{ 0x3df00000u, 0 },
{ 0x7fe00000u, 0 },
{ 0x00100000u, 0 },
{ 0x00100001u, 0 },
{ 0, 0 },
{ 0x7ff00000u, 0 },
{ 0x7ff00001u, 0 }
};
#define half C[0].d
/*
* fmal for SPARC: 128-bit quad precision, big-endian
*/
long double
__fmal(long double x, long double y, long double z) {
union {
unsigned int i[4];
long double q;
union {
unsigned int i[2];
double d;
} u;
unsigned int fsr;
volatile double dummy;
/* extract the high order words of the arguments */
xx.q = x;
yy.q = y;
zz.q = z;
/*
* distinguish zero, finite nonzero, infinite, and quiet nan
* arguments; raise invalid and return for signaling nans
*/
if (hx >= 0x7fff0000) {
if (!(hx & 0x8000)) {
/* signaling nan, raise invalid */
xx.i[0] |= 0x8000;
return (xx.q);
}
} else
} else if (hx == 0) {
/* subnormal or zero */
} else
if (hy >= 0x7fff0000) {
if (!(hy & 0x8000)) {
yy.i[0] |= 0x8000;
return (yy.q);
}
cy = 3;
} else
cy = 2;
} else if (hy == 0) {
} else
cy = 1;
if (hz >= 0x7fff0000) {
if (!(hz & 0x8000)) {
zz.i[0] |= 0x8000;
return (zz.q);
}
cz = 3;
} else
cz = 2;
} else if (hz == 0) {
} else
cz = 1;
/* get the fsr and clear current exceptions */
/* handle all other zero, inf, and nan cases */
/* if x or y is a quiet nan, return it */
if (cx == 3) {
return (x);
}
if (cy == 3) {
return (y);
}
/* if x*y is 0*inf, raise invalid and return the default nan */
zz.i[0] = 0x7fffffff;
return (zz.q);
}
/* if z is a quiet nan, return it */
if (cz == 3) {
return (z);
}
/*
* now none of x, y, or z is nan; handle cases where x or y
* is inf
*/
/*
* if z is also inf, either we have inf-inf or
* the result is the same as z depending on signs
*/
if (cz == 2) {
zz.i[0] = 0x7fffffff;
0xffffffff;
return (zz.q);
}
return (z);
}
/* otherwise the result is inf with appropriate sign */
0x7fff0000;
return (zz.q);
}
/* if z is inf, return it */
if (cz == 2) {
return (z);
}
/*
* now x, y, and z are all finite; handle cases where x or y
* is zero
*/
/* either we have 0-0 or the result is the same as z */
0) {
0;
return (zz.q);
}
return (z);
}
/* if we get here, x and y are nonzero finite, z must be zero */
return (x * y);
}
/*
* now x, y, and z are all finite and nonzero; set round-to-
* negative-infinity mode
*/
/*
* get the signs and exponents and normalize the significands
* of x and y
*/
hx &= 0xffff;
if (!ex) {
ex = 1;
xx.i[3] = 0;
ex = -31;
ex = -63;
} else {
ex = -95;
}
while ((hx & 0x10000) == 0) {
ex--;
}
} else
hx |= 0x10000;
hy &= 0xffff;
if (!ey) {
ey = 1;
yy.i[3] = 0;
ey = -31;
ey = -63;
} else {
ey = -95;
}
while ((hy & 0x10000) == 0) {
ey--;
}
} else
hy |= 0x10000;
/* convert the significands of x and y to doubles */
c = twom16;
c *= twom24;
c *= twom24;
0xffffff)) * c;
0xffffff)) * c;
c *= twom24;
0xffffff)) * c;
0xffffff)) * c;
c *= twom24;
/* form the "digits" of the product */
/* split odd-numbered terms and combine into even-numbered terms */
dxy[0] += c;
dxy[1] -= c;
dxy[3] -= c;
dxy[5] -= c;
/* propagate carries, adjusting the exponent if need be */
exy++;
}
/* extract the significand of x*y */
s = two36;
u.d = c = dxy[1] + s;
xy0 = u.i[1];
c -= s;
dxy[1] -= c;
dxy[0] -= c;
s *= twom32;
u.d = c = dxy[1] + s;
xy1 = u.i[1];
c -= s;
s *= twom32;
u.d = c = dxy[3] + s;
xy2 = u.i[1];
c -= s;
s *= twom32;
u.d = c = dxy[5] + s;
xy3 = u.i[1];
c -= s;
dxy[4] -= c;
s *= twom32;
u.d = c = dxy[5] + s;
xy4 = u.i[1];
c -= s;
s *= twom32;
u.d = c = dxy[7] + s;
xy5 = u.i[1];
c -= s;
s *= twom32;
u.d = c = dxy[8] + s;
xy6 = u.i[1];
c -= s;
dxy[8] -= c;
s *= twom32;
u.d = c = dxy[8] + s;
xy7 = u.i[1];
/* extract the sign, exponent, and significand of z */
if (!ez) {
ez = 1;
z3 = 0;
ez = -31;
ez = -63;
} else {
ez = -95;
}
while ((z0 & 0x10000) == 0) {
z3 <<= 1;
ez--;
}
} else {
z0 |= 0x10000;
}
/*
* now x*y is represented by sxy, exy, and xy[0-7], and z is
* represented likewise; swap if need be so |xy| <= |z|
*/
}
/* shift the significand of xy keeping a sticky bit */
if (e > 236) {
xy7 = 1;
} else if (e >= 224) {
if (sticky)
xy7 |= 1;
} else if (e >= 192) {
if (sticky)
xy7 |= 1;
} else if (e >= 160) {
if (sticky)
xy7 |= 1;
} else if (e >= 128) {
if (sticky)
xy7 |= 1;
} else if (e >= 96) {
if (sticky)
xy7 |= 1;
} else if (e >= 64) {
if (sticky)
xy7 |= 1;
} else if (e >= 32) {
if (sticky)
xy7 |= 1;
xy0 = 0;
} else if (e) {
if (sticky)
xy7 |= 1;
xy0 >>= e;
}
/* if this is a magnitude subtract, negate the significand of xy */
if (xy7 == 0)
if (++xy6 == 0)
if (++xy5 == 0)
if (++xy4 == 0)
if (++xy3 == 0)
if (++xy2 == 0)
if (++xy1 == 0)
xy0++;
}
/* add, propagating carries */
if (e) {
z6++;
} else
if (e) {
z5++;
} else
if (e) {
z4++;
} else
if (e) {
z3++;
} else
if (e) {
z2++;
} else
if (e) {
z1++;
} else
if (e)
z0++;
/* postnormalize and collect rounding information into z4 */
if (ez < 1) {
/* result is tiny; shift right until exponent is within range */
e = 1 - ez;
if (e > 116) {
} else if (e >= 96) {
if (sticky)
z4 |= 1;
} else if (e >= 64) {
if (sticky)
z4 |= 1;
} else if (e >= 32) {
if (sticky)
z4 |= 1;
z0 = 0;
} else {
if (sticky)
z4 |= 1;
z0 >>= e;
}
ez = 1;
} else if (z0 >= 0x20000) {
/* carry out; shift right by one */
if (sticky)
z4 |= 1;
z0 >>= 1;
ez++;
} else {
!= 0) {
/*
* borrow/cancellation; shift left as much as
* exponent allows
*/
z7 = 0;
ez -= 32;
}
z7 <<= 1;
ez--;
}
}
z4 |= 1;
}
/* get the rounding mode */
/* strip off the integer bit, if there is one */
if (ibit)
z0 -= 0x10000;
else {
ez = 0;
return (zz.q);
}
}
/*
* flip the sense of directed roundings if the result is negative;
* the logic below applies to a positive result
*/
if (sz)
/* round and raise exceptions */
if (z4) {
/* decide whether to round the fraction up */
/* round up and renormalize if necessary */
if (++z3 == 0)
if (++z2 == 0)
if (++z1 == 0)
if (++z0 == 0x10000) {
z0 = 0;
ez++;
}
}
}
if (ez >= 0x7fff) {
} else {
}
} else {
/*
* !ibit => exact result was tiny before rounding,
* z4 nonzero => result delivered is inexact
*/
if (!ibit) {
if (z4)
}
}
/* restore the fsr and emulate exceptions as needed */
else
} else {
}
} else {
}
return (zz.q);
}
static const union {
unsigned i[2];
double d;
} C[] = {
{ 0, 0x3fe00000u },
{ 0, 0x40000000u },
{ 0, 0x3df00000u },
{ 0, 0x3bf00000u },
{ 0, 0x41f00000u },
{ 0, 0x43e00000u },
{ 0, 0x7fe00000u },
{ 0, 0x00100000u },
{ 0, 0x00100001u }
};
#define half C[0].d
#if defined(__amd64)
#else
#endif
/*
* fmal for x86: 80-bit extended double precision, little-endian
*/
long double
__fmal(long double x, long double y, long double z) {
union {
unsigned i[NI];
long double e;
volatile double dummy;
/* extract the exponents of the arguments */
xx.e = x;
yy.e = y;
zz.e = z;
/* dispense with inf, nan, and zero cases */
return (x * y + z);
/*
* x * y isn't zero but could underflow to zero,
* so don't add z, lest we perturb the sign
*/
return (x * y);
/*
* now x, y, and z are all finite and nonzero; extract signs and
* normalize the significands (this will raise the denormal operand
* exception if need be)
*/
if (!ex) {
}
if (!ey) {
}
if (!ez) {
}
/*
* save the control and status words, mask all exceptions, and
* set rounding to 64-bit precision and toward-zero
*/
/* multiply x*y to 128 bits */
x = xx.e;
y = yy.e;
x *= y;
if (x >= two) {
x *= half;
y *= half;
exy++;
}
/* extract the significands */
xx.e = x;
xy4 = 0;
/*
* now x*y is represented by sxy, exy, and xy[0-4], and z is
* represented likewise; swap if need be so |xy| <= |z|
*/
}
/* shift the significand of xy keeping a sticky bit */
if (e > 130) {
xy4 = 1;
} else if (e >= 128) {
if (sticky)
xy4 |= 1;
} else if (e >= 96) {
if (sticky)
xy4 |= 1;
} else if (e >= 64) {
if (sticky)
xy4 |= 1;
} else if (e >= 32) {
if (sticky)
xy4 |= 1;
xy0 = 0;
} else if (e) {
xy0 >>= e;
}
/* if this is a magnitude subtract, negate the significand of xy */
if (xy4 == 0)
if (++xy3 == 0)
if (++xy2 == 0)
if (++xy1 == 0)
xy0++;
}
/* add, propagating carries */
if (carry) {
z3++;
} else
if (carry) {
z2++;
} else
if (carry) {
z1++;
} else
if (carry) {
z0++;
} else
/* for a magnitude subtract, ignore the last carry out */
carry = 0;
/* postnormalize and collect rounding information into z2 */
if (ez < 1) {
/* result is tiny; shift right until exponent is within range */
e = 1 - ez;
if (e > 67) {
} else if (e >= 64) {
if (sticky)
z2 |= 1;
z0 = 0;
} else if (e >= 32) {
if (sticky)
z2 |= 1;
} else {
if (sticky)
z2 |= 1;
}
ez = 1;
} else if (carry) {
/* carry out; shift right by one */
if (sticky)
z2 |= 1;
ez++;
} else {
/*
* borrow/cancellation; shift left as much as
* exponent allows
*/
z4 = 0;
ez -= 32;
}
z4 <<= 1;
ez--;
}
}
z2 |= 1;
}
/* get the rounding mode */
/* adjust exponent if result is subnormal */
tinyafter = 0;
if (!(z0 & 0x80000000)) {
ez = 0;
tinyafter = 1;
return (zz.e);
}
}
/*
* flip the sense of directed roundings if the result is negative;
* the logic below applies to a positive result
*/
/* round */
if (z2) {
/* round up and renormalize if necessary */
if (++z1 == 0) {
if (++z0 == 0) {
z0 = 0x80000000;
ez++;
} else if (z0 == 0x80000000) {
/* rounded up to smallest normal */
ez = 1;
z2 >= 0xc0000000u))
/*
* would have rounded up to
* smallest normal even with
* unbounded range
*/
tinyafter = 0;
}
}
}
}
if (ez >= 0x7fff) {
zz.i[0] = 0;
} else {
zz.i[0] = 0xffffffff;
}
} else {
/*
* tinyafter => result rounded w/ unbounded range would be tiny,
* z2 nonzero => result delivered is inexact
*/
if (tinyafter) {
if (z2)
else
} else if (z2) {
}
}
return (zz.e);
}
#else
#endif