From b08d204a37cc370fcb1515ac3fb31d452b3bcc65 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Feb 2021 13:33:59 -0500 Subject: [PATCH] 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 --- qemu/aarch64.h | 2 + qemu/aarch64eb.h | 2 + qemu/arm.h | 2 + qemu/armeb.h | 2 + qemu/fpu/softfloat.c | 49 ++++++++++++++++----- qemu/header_gen.py | 2 + qemu/include/fpu/softfloat.h | 2 + qemu/m68k.h | 2 + qemu/mips.h | 2 + qemu/mips64.h | 2 + qemu/mips64el.h | 2 + qemu/mipsel.h | 2 + qemu/powerpc.h | 2 + qemu/riscv32.h | 2 + qemu/riscv64.h | 2 + qemu/sparc.h | 2 + qemu/sparc64.h | 2 + qemu/target/m68k/softfloat.c | 83 ------------------------------------ qemu/target/m68k/softfloat.h | 1 - qemu/x86_64.h | 2 + 20 files changed, 72 insertions(+), 95 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 11013a22..6d6c2ff5 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -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 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index edb24383..b04e69c0 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -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 diff --git a/qemu/arm.h b/qemu/arm.h index df3fb8d2..7924c55e 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -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 diff --git a/qemu/armeb.h b/qemu/armeb.h index 9a93d4d5..2f6ba0a4 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -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 diff --git a/qemu/fpu/softfloat.c b/qemu/fpu/softfloat.c index 564ff17c..15de9697 100644 --- a/qemu/fpu/softfloat.c +++ b/qemu/fpu/softfloat.c @@ -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,14 +5743,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( @@ -5755,6 +5760,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 diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 1e53dcda..f86bd564 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -684,6 +684,8 @@ symbols = ( 'floatx80_le_quiet', 'floatx80_lt', 'floatx80_lt_quiet', + 'floatx80_mod', + 'floatx80_modrem', 'floatx80_mul', 'floatx80_rem', 'floatx80_round', diff --git a/qemu/include/fpu/softfloat.h b/qemu/include/fpu/softfloat.h index 3884997e..cd8a3e6d 100644 --- a/qemu/include/fpu/softfloat.h +++ b/qemu/include/fpu/softfloat.h @@ -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); diff --git a/qemu/m68k.h b/qemu/m68k.h index c9ddb7a4..b39e30be 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -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 diff --git a/qemu/mips.h b/qemu/mips.h index 950adea5..80b4d8e9 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -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 diff --git a/qemu/mips64.h b/qemu/mips64.h index ee78ef89..2d925d79 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -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 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 16fcda96..53b9cf46 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -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 diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 9357185c..2fd410c1 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -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 diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 7939f57b..53cb087c 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -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 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 40bd2cc1..ec2d8a9c 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -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 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index a1bbc53d..9d7339c0 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -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 diff --git a/qemu/sparc.h b/qemu/sparc.h index b1f15104..7a8710f2 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -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 diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 47d80a80..e77487d3 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -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 diff --git a/qemu/target/m68k/softfloat.c b/qemu/target/m68k/softfloat.c index 9f120cf1..b6d0ed7a 100644 --- a/qemu/target/m68k/softfloat.c +++ b/qemu/target/m68k/softfloat.c @@ -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'. diff --git a/qemu/target/m68k/softfloat.h b/qemu/target/m68k/softfloat.h index 365ef6ac..4bb95671 100644 --- a/qemu/target/m68k/softfloat.h +++ b/qemu/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); diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 29f0699f..59f509f2 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -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