FPREM/FPREM1 fix

This commit is contained in:
Stanislav Shwartsman 2010-03-22 22:11:00 +00:00
parent e757d6d030
commit bfde54f9ca
3 changed files with 46 additions and 26 deletions

View File

@ -45,7 +45,7 @@ static Bit64u remainder_kernel(Bit64u aSig0, Bit64u bSig, int expDiff, Bit64u *z
return q;
}
static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, float_status_t &status)
static int do_fprem(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, int rounding_mode, float_status_t &status)
{
Bit32s aExp, bExp, zExp, expDiff;
Bit64u aSig0, aSig1, bSig;
@ -56,7 +56,8 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b))
{
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
r = floatx80_default_nan;
return -1;
}
aSig0 = extractFloatx80Frac(a);
@ -67,50 +68,66 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig0<<1) || ((bExp == 0x7FFF) && (Bit64u) (bSig<<1))) {
return propagateFloatx80NaN(a, b, status);
r = propagateFloatx80NaN(a, b, status);
return -1;
}
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
r = floatx80_default_nan;
return -1;
}
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
if ((Bit64u) (bSig<<1)) {
r = propagateFloatx80NaN(a, b, status);
return -1;
}
if (aExp == 0 && aSig0) {
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
return (a.fraction & BX_CONST64(0x8000000000000000)) ?
r = (a.fraction & BX_CONST64(0x8000000000000000)) ?
packFloatx80(aSign, aExp, aSig0) : a;
return 0;
}
return a;
r = a;
return 0;
}
if (bExp == 0) {
if (bSig == 0) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
r = floatx80_default_nan;
return -1;
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0) {
if (aSig0 == 0) return a;
if (aSig0 == 0) {
r = a;
return 0;
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
}
expDiff = aExp - bExp;
aSig1 = 0;
Bit32u overflow = 0;
if (expDiff >= 64) {
int n = (expDiff & 0x1f) | 0x20;
remainder_kernel(aSig0, bSig, n, &aSig0, &aSig1);
zExp = aExp - n;
q = (Bit64u) -1;
overflow = 1;
}
else {
zExp = bExp;
if (expDiff < 0) {
if (expDiff < -1)
return (a.fraction & BX_CONST64(0x8000000000000000)) ?
if (expDiff < -1) {
r = (a.fraction & BX_CONST64(0x8000000000000000)) ?
packFloatx80(aSign, aExp, aSig0) : a;
return 0;
}
shift128Right(aSig0, 0, 1, &aSig0, &aSig1);
expDiff = 0;
}
@ -144,7 +161,8 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
}
}
return normalizeRoundAndPackFloatx80(80, aSign, zExp, aSig0, aSig1, status);
r = normalizeRoundAndPackFloatx80(80, aSign, zExp, aSig0, aSig1, status);
return overflow;
}
/*----------------------------------------------------------------------------
@ -153,9 +171,9 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 floatx80_ieee754_remainder(floatx80 a, floatx80 b, Bit64u &q, float_status_t &status)
int floatx80_ieee754_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status)
{
return do_fprem(a, b, q, float_round_nearest_even, status);
return do_fprem(a, b, r, q, float_round_nearest_even, status);
}
/*----------------------------------------------------------------------------
@ -167,7 +185,7 @@ floatx80 floatx80_ieee754_remainder(floatx80 a, floatx80 b, Bit64u &q, float_sta
| quotient of 'a' divided by 'b' to an integer.
*----------------------------------------------------------------------------*/
floatx80 floatx80_remainder(floatx80 a, floatx80 b, Bit64u &q, float_status_t &status)
int floatx80_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status)
{
return do_fprem(a, b, q, float_round_to_zero, status);
return do_fprem(a, b, r, q, float_round_to_zero, status);
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: fpu_trans.cc,v 1.28 2010-03-22 18:09:40 sshwarts Exp $
// $Id: fpu_trans.cc,v 1.29 2010-03-22 22:11:00 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
@ -224,13 +224,14 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM1(bxInstruction_c *i)
floatx80 a = BX_READ_FPU_REG(0);
floatx80 b = BX_READ_FPU_REG(1);
floatx80 result;
floatx80 result = floatx80_ieee754_remainder(a, b, quotient, status);
int flags = floatx80_ieee754_remainder(a, b, result, quotient, status);
if (! FPU_exception(status.float_exception_flags)) {
if (! floatx80_is_nan(result)) {
if (flags >= 0) {
int cc = 0;
if (quotient == (Bit64u) -1) cc = FPU_SW_C2;
if (flags) cc = FPU_SW_C2;
else {
if (quotient & 1) cc |= FPU_SW_C1;
if (quotient & 2) cc |= FPU_SW_C3;
@ -264,13 +265,14 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM(bxInstruction_c *i)
floatx80 a = BX_READ_FPU_REG(0);
floatx80 b = BX_READ_FPU_REG(1);
floatx80 result;
floatx80 result = floatx80_remainder(a, b, quotient, status);
int flags = floatx80_remainder(a, b, result, quotient, status);
if (! FPU_exception(status.float_exception_flags)) {
if (! floatx80_is_nan(result)) {
if (flags >= 0) {
int cc = 0;
if (quotient == (Bit64u) -1) cc = FPU_SW_C2;
if (flags) cc = FPU_SW_C2;
else {
if (quotient & 1) cc |= FPU_SW_C1;
if (quotient & 2) cc |= FPU_SW_C3;

View File

@ -43,8 +43,8 @@ Bit16s floatx80_to_int16_round_to_zero(floatx80, float_status_t &status);
float_class_t floatx80_class(floatx80);
floatx80 floatx80_extract(floatx80 &a, float_status_t &status);
floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status_t &status);
floatx80 floatx80_remainder(floatx80 a, floatx80 b, Bit64u &q, float_status_t &status);
floatx80 floatx80_ieee754_remainder(floatx80 a, floatx80 b, Bit64u &q, float_status_t &status);
int floatx80_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status);
int floatx80_ieee754_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status);
floatx80 f2xm1(floatx80 a, float_status_t &status);
floatx80 fyl2x(floatx80 a, floatx80 b, float_status_t &status);
floatx80 fyl2xp1(floatx80 a, floatx80 b, float_status_t &status);