softfloat: merge floatx80_mod and floatx80_rem

The m68k-specific softfloat code includes a function floatx80_mod that
is extremely similar to floatx80_rem, but computing the remainder
based on truncating the quotient toward zero rather than rounding it
to nearest integer. This is also useful for emulating the x87 fprem
and fprem1 instructions. Change the floatx80_rem implementation into
floatx80_modrem that can perform either operation, with both
floatx80_rem and floatx80_mod as thin wrappers available for all
targets.

There does not appear to be any use for the _mod operation for other
floating-point formats in QEMU (the only other architectures using
_rem at all are linux-user/arm/nwfpe, for FPA emulation, and openrisc,
for instructions that have been removed in the latest version of the
architecture), so no change is made to the code for other formats.

Backports commit 6b8b0136ab3018e4b552b485f808bf66bcf19ead from qemu
This commit is contained in:
Joseph Myers 2021-02-25 13:33:59 -05:00 committed by Lioncash
parent 2aee4714ab
commit b08d204a37
20 changed files with 72 additions and 95 deletions

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_aarch64
#define floatx80_lt floatx80_lt_aarch64
#define floatx80_lt_quiet floatx80_lt_quiet_aarch64
#define floatx80_mod floatx80_mod_aarch64
#define floatx80_modrem floatx80_modrem_aarch64
#define floatx80_mul floatx80_mul_aarch64
#define floatx80_rem floatx80_rem_aarch64
#define floatx80_round floatx80_round_aarch64

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_aarch64eb
#define floatx80_lt floatx80_lt_aarch64eb
#define floatx80_lt_quiet floatx80_lt_quiet_aarch64eb
#define floatx80_mod floatx80_mod_aarch64eb
#define floatx80_modrem floatx80_modrem_aarch64eb
#define floatx80_mul floatx80_mul_aarch64eb
#define floatx80_rem floatx80_rem_aarch64eb
#define floatx80_round floatx80_round_aarch64eb

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_arm
#define floatx80_lt floatx80_lt_arm
#define floatx80_lt_quiet floatx80_lt_quiet_arm
#define floatx80_mod floatx80_mod_arm
#define floatx80_modrem floatx80_modrem_arm
#define floatx80_mul floatx80_mul_arm
#define floatx80_rem floatx80_rem_arm
#define floatx80_round floatx80_round_arm

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_armeb
#define floatx80_lt floatx80_lt_armeb
#define floatx80_lt_quiet floatx80_lt_quiet_armeb
#define floatx80_mod floatx80_mod_armeb
#define floatx80_modrem floatx80_modrem_armeb
#define floatx80_mul floatx80_mul_armeb
#define floatx80_rem floatx80_rem_armeb
#define floatx80_round floatx80_round_armeb

View file

@ -5659,10 +5659,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;
@ -5708,7 +5711,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;
}
@ -5740,6 +5743,7 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
term1 = 0;
term0 = bSig;
}
if (!mod) {
sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
|| ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
@ -5749,12 +5753,35 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
aSig1 = alternateASig1;
zSign = ! zSign;
}
}
return
normalizeRoundAndPackFloatx80(
80, zSign, bExp + expDiff, aSig0, aSig1, 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

View file

@ -684,6 +684,8 @@ symbols = (
'floatx80_le_quiet',
'floatx80_lt',
'floatx80_lt_quiet',
'floatx80_mod',
'floatx80_modrem',
'floatx80_mul',
'floatx80_rem',
'floatx80_round',

View file

@ -690,6 +690,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);

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_m68k
#define floatx80_lt floatx80_lt_m68k
#define floatx80_lt_quiet floatx80_lt_quiet_m68k
#define floatx80_mod floatx80_mod_m68k
#define floatx80_modrem floatx80_modrem_m68k
#define floatx80_mul floatx80_mul_m68k
#define floatx80_rem floatx80_rem_m68k
#define floatx80_round floatx80_round_m68k

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_mips
#define floatx80_lt floatx80_lt_mips
#define floatx80_lt_quiet floatx80_lt_quiet_mips
#define floatx80_mod floatx80_mod_mips
#define floatx80_modrem floatx80_modrem_mips
#define floatx80_mul floatx80_mul_mips
#define floatx80_rem floatx80_rem_mips
#define floatx80_round floatx80_round_mips

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_mips64
#define floatx80_lt floatx80_lt_mips64
#define floatx80_lt_quiet floatx80_lt_quiet_mips64
#define floatx80_mod floatx80_mod_mips64
#define floatx80_modrem floatx80_modrem_mips64
#define floatx80_mul floatx80_mul_mips64
#define floatx80_rem floatx80_rem_mips64
#define floatx80_round floatx80_round_mips64

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_mips64el
#define floatx80_lt floatx80_lt_mips64el
#define floatx80_lt_quiet floatx80_lt_quiet_mips64el
#define floatx80_mod floatx80_mod_mips64el
#define floatx80_modrem floatx80_modrem_mips64el
#define floatx80_mul floatx80_mul_mips64el
#define floatx80_rem floatx80_rem_mips64el
#define floatx80_round floatx80_round_mips64el

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_mipsel
#define floatx80_lt floatx80_lt_mipsel
#define floatx80_lt_quiet floatx80_lt_quiet_mipsel
#define floatx80_mod floatx80_mod_mipsel
#define floatx80_modrem floatx80_modrem_mipsel
#define floatx80_mul floatx80_mul_mipsel
#define floatx80_rem floatx80_rem_mipsel
#define floatx80_round floatx80_round_mipsel

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_powerpc
#define floatx80_lt floatx80_lt_powerpc
#define floatx80_lt_quiet floatx80_lt_quiet_powerpc
#define floatx80_mod floatx80_mod_powerpc
#define floatx80_modrem floatx80_modrem_powerpc
#define floatx80_mul floatx80_mul_powerpc
#define floatx80_rem floatx80_rem_powerpc
#define floatx80_round floatx80_round_powerpc

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_riscv32
#define floatx80_lt floatx80_lt_riscv32
#define floatx80_lt_quiet floatx80_lt_quiet_riscv32
#define floatx80_mod floatx80_mod_riscv32
#define floatx80_modrem floatx80_modrem_riscv32
#define floatx80_mul floatx80_mul_riscv32
#define floatx80_rem floatx80_rem_riscv32
#define floatx80_round floatx80_round_riscv32

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_riscv64
#define floatx80_lt floatx80_lt_riscv64
#define floatx80_lt_quiet floatx80_lt_quiet_riscv64
#define floatx80_mod floatx80_mod_riscv64
#define floatx80_modrem floatx80_modrem_riscv64
#define floatx80_mul floatx80_mul_riscv64
#define floatx80_rem floatx80_rem_riscv64
#define floatx80_round floatx80_round_riscv64

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_sparc
#define floatx80_lt floatx80_lt_sparc
#define floatx80_lt_quiet floatx80_lt_quiet_sparc
#define floatx80_mod floatx80_mod_sparc
#define floatx80_modrem floatx80_modrem_sparc
#define floatx80_mul floatx80_mul_sparc
#define floatx80_rem floatx80_rem_sparc
#define floatx80_round floatx80_round_sparc

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_sparc64
#define floatx80_lt floatx80_lt_sparc64
#define floatx80_lt_quiet floatx80_lt_quiet_sparc64
#define floatx80_mod floatx80_mod_sparc64
#define floatx80_modrem floatx80_modrem_sparc64
#define floatx80_mul floatx80_mul_sparc64
#define floatx80_rem floatx80_rem_sparc64
#define floatx80_round floatx80_round_sparc64

View file

@ -42,89 +42,6 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
return a;
}
/*
* 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'.

View file

@ -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);

View file

@ -678,6 +678,8 @@
#define floatx80_le_quiet floatx80_le_quiet_x86_64
#define floatx80_lt floatx80_lt_x86_64
#define floatx80_lt_quiet floatx80_lt_quiet_x86_64
#define floatx80_mod floatx80_mod_x86_64
#define floatx80_modrem floatx80_modrem_x86_64
#define floatx80_mul floatx80_mul_x86_64
#define floatx80_rem floatx80_rem_x86_64
#define floatx80_round floatx80_round_x86_64