void fex_merge_flags(const fenv_t *p) { unsigned long fsr; __fenv_getfsr(&fsr); __fenv_set_ex(fsr, __fenv_get_ex(fsr) | __fenv_get_ex(p->__fsr)); __fenv_setfsr(&fsr); if (fex_get_log()) __fex_update_te(); }
/* * fmal for SPARC: 128-bit quad precision, big-endian */ long double __fmal(long double x, long double y, long double z) { union { unsigned i[4]; long double q; } xx, yy, zz; union { unsigned i[2]; double d; } u; double dx[5], dy[5], dxy[9], c, s; unsigned xy0, xy1, xy2, xy3, xy4, xy5, xy6, xy7; unsigned z0, z1, z2, z3, z4, z5, z6, z7; unsigned fsr, rm, sticky; int hx, hy, hz, ex, ey, ez, exy, sxy, sz, e, ibit; int cx, cy, cz; volatile double dummy; /* extract the high order words of the arguments */ xx.q = x; yy.q = y; zz.q = z; hx = xx.i[0] & ~0x80000000; hy = yy.i[0] & ~0x80000000; hz = zz.i[0] & ~0x80000000; /* * distinguish zero, finite nonzero, infinite, and quiet nan * arguments; raise invalid and return for signaling nans */ if (hx >= 0x7fff0000) { if ((hx & 0xffff) | xx.i[1] | xx.i[2] | xx.i[3]) { if (!(hx & 0x8000)) { /* signaling nan, raise invalid */ dummy = snan; dummy += snan; xx.i[0] |= 0x8000; return (xx.q); } cx = 3; /* quiet nan */ } else cx = 2; /* inf */ } else if (hx == 0) { cx = (xx.i[1] | xx.i[2] | xx.i[3]) ? 1 : 0; /* subnormal or zero */ } else cx = 1; /* finite nonzero */ if (hy >= 0x7fff0000) { if ((hy & 0xffff) | yy.i[1] | yy.i[2] | yy.i[3]) { if (!(hy & 0x8000)) { dummy = snan; dummy += snan; yy.i[0] |= 0x8000; return (yy.q); } cy = 3; } else cy = 2; } else if (hy == 0) { cy = (yy.i[1] | yy.i[2] | yy.i[3]) ? 1 : 0; } else cy = 1; if (hz >= 0x7fff0000) { if ((hz & 0xffff) | zz.i[1] | zz.i[2] | zz.i[3]) { if (!(hz & 0x8000)) { dummy = snan; dummy += snan; zz.i[0] |= 0x8000; return (zz.q); } cz = 3; } else cz = 2; } else if (hz == 0) { cz = (zz.i[1] | zz.i[2] | zz.i[3]) ? 1 : 0; } else cz = 1; /* get the fsr and clear current exceptions */ __fenv_getfsr(&fsr); fsr &= ~FSR_CEXC; /* handle all other zero, inf, and nan cases */ if (cx != 1 || cy != 1 || cz != 1) { /* if x or y is a quiet nan, return it */ if (cx == 3) { __fenv_setfsr(&fsr); return (x); } if (cy == 3) { __fenv_setfsr(&fsr); return (y); } /* if x*y is 0*inf, raise invalid and return the default nan */ if ((cx == 0 && cy == 2) || (cx == 2 && cy == 0)) { dummy = zero; dummy *= inf; zz.i[0] = 0x7fffffff; zz.i[1] = zz.i[2] = zz.i[3] = 0xffffffff; return (zz.q); } /* if z is a quiet nan, return it */ if (cz == 3) { __fenv_setfsr(&fsr); return (z); } /* * now none of x, y, or z is nan; handle cases where x or y * is inf */ if (cx == 2 || cy == 2) { /* * if z is also inf, either we have inf-inf or * the result is the same as z depending on signs */ if (cz == 2) { if ((int) ((xx.i[0] ^ yy.i[0]) ^ zz.i[0]) < 0) { dummy = inf; dummy -= inf; zz.i[0] = 0x7fffffff; zz.i[1] = zz.i[2] = zz.i[3] = 0xffffffff; return (zz.q); } __fenv_setfsr(&fsr); return (z); } /* otherwise the result is inf with appropriate sign */ zz.i[0] = ((xx.i[0] ^ yy.i[0]) & 0x80000000) | 0x7fff0000; zz.i[1] = zz.i[2] = zz.i[3] = 0; __fenv_setfsr(&fsr); return (zz.q); } /* if z is inf, return it */ if (cz == 2) { __fenv_setfsr(&fsr); return (z); } /* * now x, y, and z are all finite; handle cases where x or y * is zero */ if (cx == 0 || cy == 0) { /* either we have 0-0 or the result is the same as z */ if (cz == 0 && (int) ((xx.i[0] ^ yy.i[0]) ^ zz.i[0]) < 0) { zz.i[0] = (fsr >> 30) == FSR_RM ? 0x80000000 : 0; __fenv_setfsr(&fsr); return (zz.q); } __fenv_setfsr(&fsr); return (z); } /* if we get here, x and y are nonzero finite, z must be zero */ return (x * y); }
int fesetenv(const fenv_t *p) { __fenv_setfsr(&p->__fsr); fex_setexcepthandler(&p->__handlers, FEX_ALL); return 0; }