sparc: fix NaN handling
authorBlue Swirl <blauwirbel@gmail.com>
Tue, 18 Jan 2011 21:34:51 +0000 (21:34 +0000)
committerBlue Swirl <blauwirbel@gmail.com>
Tue, 18 Jan 2011 21:34:51 +0000 (21:34 +0000)
Fix several bugs in NaN handling:
 * e in fcmpe* only changes qNaN handling
 * FCC is unchanged if an exception is raised
 * clear previous FTT before setting it

Reported-by: Mateusz Loskot <mateusz@loskot.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
target-sparc/op_helper.c

index 58f9f82f524b0e4225f6368e0cb8859bc9500929..b70970ac2a0b0832ab18311eb3b8f67b11baff03 100644 (file)
@@ -857,65 +857,77 @@ void helper_fsqrtq(void)
     QT0 = float128_sqrt(QT1, &env->fp_status);
 }
 
-#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
+#define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
     void glue(helper_, name) (void)                                     \
     {                                                                   \
-        target_ulong new_fsr;                                           \
-                                                                        \
-        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
+                     glue(size, _is_any_nan)(reg2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
-            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
-            if ((env->fsr & FSR_NVM) || TRAP) {                         \
-                env->fsr |= new_fsr;                                    \
+            if ((env->fsr & FSR_NVM)) {                                 \
                 env->fsr |= FSR_NVC;                                    \
                 env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
                 env->fsr |= FSR_NVA;                                    \
             }                                                           \
             break;                                                      \
         case float_relation_less:                                       \
-            new_fsr = FSR_FCC0 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
             break;                                                      \
         case float_relation_greater:                                    \
-            new_fsr = FSR_FCC1 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
             break;                                                      \
         default:                                                        \
-            new_fsr = 0;                                                \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
             break;                                                      \
         }                                                               \
-        env->fsr |= new_fsr;                                            \
     }
-#define GEN_FCMPS(name, size, FS, TRAP)                                 \
+#define GEN_FCMPS(name, size, FS, E)                                    \
     void glue(helper_, name)(float32 src1, float32 src2)                \
     {                                                                   \
-        target_ulong new_fsr;                                           \
-                                                                        \
-        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
+        env->fsr &= FSR_FTT_NMASK;                                      \
+        if (E && (glue(size, _is_any_nan)(src1) ||                      \
+                     glue(size, _is_any_nan)(src2)) &&                  \
+            (env->fsr & FSR_NVM)) {                                     \
+            env->fsr |= FSR_NVC;                                        \
+            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
+            raise_exception(TT_FP_EXCP);                                \
+        }                                                               \
         switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
-            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
-            if ((env->fsr & FSR_NVM) || TRAP) {                         \
-                env->fsr |= new_fsr;                                    \
+            if ((env->fsr & FSR_NVM)) {                                 \
                 env->fsr |= FSR_NVC;                                    \
                 env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
+                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
+                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
                 env->fsr |= FSR_NVA;                                    \
             }                                                           \
             break;                                                      \
         case float_relation_less:                                       \
-            new_fsr = FSR_FCC0 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC0 << FS;                                 \
             break;                                                      \
         case float_relation_greater:                                    \
-            new_fsr = FSR_FCC1 << FS;                                   \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            env->fsr |= FSR_FCC1 << FS;                                 \
             break;                                                      \
         default:                                                        \
-            new_fsr = 0;                                                \
+            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
             break;                                                      \
         }                                                               \
-        env->fsr |= new_fsr;                                            \
     }
 
 GEN_FCMPS(fcmps, float32, 0, 0);