aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2020-05-04 23:40:20 +0000
committerRichard Henderson <richard.henderson@linaro.org>2020-05-15 11:04:50 -0700
commit9ecaf5ccec13ff2e8fe1e72f6e0f3367d2169c1c (patch)
treeb51a6862e2ea9ddeaf179d2526de717ffa336c66
parentbe53fa785ab766d2722628403edee75b3e6ab599 (diff)
downloadqemu-9ecaf5ccec13ff2e8fe1e72f6e0f3367d2169c1c.zip
qemu-9ecaf5ccec13ff2e8fe1e72f6e0f3367d2169c1c.tar.gz
qemu-9ecaf5ccec13ff2e8fe1e72f6e0f3367d2169c1c.tar.bz2
softfloat: fix floatx80 pseudo-denormal round to integer
The softfloat function floatx80_round_to_int incorrectly handles the case of a pseudo-denormal where only the high bit of the significand is set, ignoring that bit (treating the number as an exact zero) rather than treating the number as an alternative representation of +/- 2^-16382 (which may round to +/- 1 depending on the rounding mode) as hardware does. Fix this check (simplifying the code in the process). Signed-off-by: Joseph Myers <joseph@codesourcery.com> Message-Id: <alpine.DEB.2.21.2005042339420.22972@digraph.polyomino.org.uk> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--fpu/softfloat.c2
-rw-r--r--tests/tcg/i386/test-i386-pseudo-denormal.c10
2 files changed, 11 insertions, 1 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index c57f72e..a362bf8 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -5741,7 +5741,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
}
if ( aExp < 0x3FFF ) {
if ( ( aExp == 0 )
- && ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
+ && ( (uint64_t) ( extractFloatx80Frac( a ) ) == 0 ) ) {
return a;
}
status->float_exception_flags |= float_flag_inexact;
diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c
index acf2b9c..00d510c 100644
--- a/tests/tcg/i386/test-i386-pseudo-denormal.c
+++ b/tests/tcg/i386/test-i386-pseudo-denormal.c
@@ -14,6 +14,7 @@ volatile long double ld_res;
int main(void)
{
+ short cw;
int ret = 0;
ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld;
if (ld_res != 0x1p-16381L) {
@@ -24,5 +25,14 @@ int main(void)
printf("FAIL: pseudo-denormal compare\n");
ret = 1;
}
+ /* Set round-upward. */
+ __asm__ volatile ("fnstcw %0" : "=m" (cw));
+ cw = (cw & ~0xc00) | 0x800;
+ __asm__ volatile ("fldcw %0" : : "m" (cw));
+ __asm__ ("frndint" : "=t" (ld_res) : "0" (ld_pseudo_m16382.ld));
+ if (ld_res != 1.0L) {
+ printf("FAIL: pseudo-denormal round-to-integer\n");
+ ret = 1;
+ }
return ret;
}