]> xenbits.xensource.com Git - qemu-xen.git/commitdiff
softfloat: fix floatx80 pseudo-denormal round to integer
authorJoseph Myers <joseph@codesourcery.com>
Mon, 4 May 2020 23:40:20 +0000 (23:40 +0000)
committerRichard Henderson <richard.henderson@linaro.org>
Fri, 15 May 2020 18:04:50 +0000 (11:04 -0700)
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>
fpu/softfloat.c
tests/tcg/i386/test-i386-pseudo-denormal.c

index c57f72e3a637ae1cd8db6fa4edae73bb5fe10d9c..a362bf89cad64b5adc03b93557941742d8a0ebd5 100644 (file)
@@ -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;
index acf2b9cf037f67da6137b244ad234e58cf42ccc6..00d510cf4a105197308cdedbfa1674d1454af6ff 100644 (file)
@@ -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;
 }