aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fpu/softfloat.c49
-rw-r--r--include/fpu/softfloat.h2
-rw-r--r--target/m68k/softfloat.c83
-rw-r--r--target/m68k/softfloat.h1
4 files changed, 40 insertions, 95 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 5e9746c287..b7dcf4d6c3 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -5697,10 +5697,13 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
/*----------------------------------------------------------------------------
| Returns the remainder of the extended double-precision floating-point value
| `a' with respect to the corresponding value `b'. The operation is performed
-| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic,
+| if 'mod' is false; if 'mod' is true, return the remainder based on truncating
+| the quotient toward zero instead.
*----------------------------------------------------------------------------*/
-floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
+floatx80 floatx80_modrem(floatx80 a, floatx80 b, bool mod,
+ float_status *status)
{
bool aSign, zSign;
int32_t aExp, bExp, expDiff;
@@ -5746,7 +5749,7 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
expDiff = aExp - bExp;
aSig1 = 0;
if ( expDiff < 0 ) {
- if ( expDiff < -1 ) return a;
+ if ( mod || expDiff < -1 ) return a;
shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
expDiff = 0;
}
@@ -5778,14 +5781,16 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
term1 = 0;
term0 = bSig;
}
- sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
- if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
- || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
- && ( q & 1 ) )
- ) {
- aSig0 = alternateASig0;
- aSig1 = alternateASig1;
- zSign = ! zSign;
+ if (!mod) {
+ sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
+ if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ && ( q & 1 ) )
+ ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ zSign = ! zSign;
+ }
}
return
normalizeRoundAndPackFloatx80(
@@ -5794,6 +5799,28 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
}
/*----------------------------------------------------------------------------
+| Returns the remainder of the extended double-precision floating-point value
+| `a' with respect to the corresponding value `b'. The operation is performed
+| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
+{
+ return floatx80_modrem(a, b, false, status);
+}
+
+/*----------------------------------------------------------------------------
+| Returns the remainder of the extended double-precision floating-point value
+| `a' with respect to the corresponding value `b', with the quotient truncated
+| toward zero.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status)
+{
+ return floatx80_modrem(a, b, true, status);
+}
+
+/*----------------------------------------------------------------------------
| Returns the square root of the extended double-precision floating-point
| value `a'. The operation is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 16ca697a73..bff6934d09 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -687,6 +687,8 @@ floatx80 floatx80_add(floatx80, floatx80, float_status *status);
floatx80 floatx80_sub(floatx80, floatx80, float_status *status);
floatx80 floatx80_mul(floatx80, floatx80, float_status *status);
floatx80 floatx80_div(floatx80, floatx80, float_status *status);
+floatx80 floatx80_modrem(floatx80, floatx80, bool, float_status *status);
+floatx80 floatx80_mod(floatx80, floatx80, float_status *status);
floatx80 floatx80_rem(floatx80, floatx80, float_status *status);
floatx80 floatx80_sqrt(floatx80, float_status *status);
FloatRelation floatx80_compare(floatx80, floatx80, float_status *status);
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 9f120cf15e..b6d0ed7acf 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -43,89 +43,6 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
}
/*
- * Returns the modulo remainder of the extended double-precision floating-point
- * value `a' with respect to the corresponding value `b'.
- */
-
-floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status)
-{
- bool aSign, zSign;
- int32_t aExp, bExp, expDiff;
- uint64_t aSig0, aSig1, bSig;
- uint64_t qTemp, term0, term1;
-
- aSig0 = extractFloatx80Frac(a);
- aExp = extractFloatx80Exp(a);
- aSign = extractFloatx80Sign(a);
- bSig = extractFloatx80Frac(b);
- bExp = extractFloatx80Exp(b);
-
- if (aExp == 0x7FFF) {
- if ((uint64_t) (aSig0 << 1)
- || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) {
- return propagateFloatx80NaN(a, b, status);
- }
- goto invalid;
- }
- if (bExp == 0x7FFF) {
- if ((uint64_t) (bSig << 1)) {
- return propagateFloatx80NaN(a, b, status);
- }
- return a;
- }
- if (bExp == 0) {
- if (bSig == 0) {
- invalid:
- float_raise(float_flag_invalid, status);
- return floatx80_default_nan(status);
- }
- normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
- }
- if (aExp == 0) {
- if ((uint64_t) (aSig0 << 1) == 0) {
- return a;
- }
- normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
- }
- bSig |= UINT64_C(0x8000000000000000);
- zSign = aSign;
- expDiff = aExp - bExp;
- aSig1 = 0;
- if (expDiff < 0) {
- return a;
- }
- qTemp = (bSig <= aSig0);
- if (qTemp) {
- aSig0 -= bSig;
- }
- expDiff -= 64;
- while (0 < expDiff) {
- qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
- qTemp = (2 < qTemp) ? qTemp - 2 : 0;
- mul64To128(bSig, qTemp, &term0, &term1);
- sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
- shortShift128Left(aSig0, aSig1, 62, &aSig0, &aSig1);
- expDiff -= 62;
- }
- expDiff += 64;
- if (0 < expDiff) {
- qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
- qTemp = (2 < qTemp) ? qTemp - 2 : 0;
- qTemp >>= 64 - expDiff;
- mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1);
- sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
- shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1);
- while (le128(term0, term1, aSig0, aSig1)) {
- ++qTemp;
- sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
- }
- }
- return
- normalizeRoundAndPackFloatx80(
- 80, zSign, bExp + expDiff, aSig0, aSig1, status);
-}
-
-/*
* Returns the mantissa of the extended double-precision floating-point
* value `a'.
*/
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index 365ef6ac7a..4bb9567134 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -23,7 +23,6 @@
#define TARGET_M68K_SOFTFLOAT_H
#include "fpu/softfloat.h"
-floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status);
floatx80 floatx80_getman(floatx80 a, float_status *status);
floatx80 floatx80_getexp(floatx80 a, float_status *status);
floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status);