qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 6/7] softfloat: Add SoftFloat status `nan2008_mode'


From: Maciej W. Rozycki
Subject: [Qemu-devel] [PATCH 6/7] softfloat: Add SoftFloat status `nan2008_mode' flag
Date: Tue, 9 Dec 2014 01:55:54 +0000
User-agent: Alpine 1.10 (DEB 962 2008-03-14)

Add support for switching between legacy NaN and IEEE 754-2008 NaN modes 
where required, currently for the MIPS target only.  Also handle the 
saving and restoration of the `nan2008_mode' status flag.

Use qNaN bit patterns for the 2008 NaN mode as from revision 5.00 [1][2] 
of the MIPS Architecture, updated from revision 3.50 that used a 
different choice.

References:

[1] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS32 Architecture", MIPS Technologies, Inc., Document Number:
    MD00082, Revision 5.02, April 30, 2013, Table 5.3 "Value Supplied 
    When a New Quiet NaN Is Created", p. 73

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
    MD00083, Revision 5.01, December 15, 2012, Table 5.3 "Value Supplied 
    When a New Quiet NaN Is Created", p. 73

Signed-off-by: Thomas Schwinge <address@hidden>
Signed-off-by: Maciej W. Rozycki <address@hidden>
---
 I missed revision 5.00 of the architecture documents before they were 
taken offline; however there have been no changes to Table 5.3 between 
revision 5.00 and, respectively, revisions 5.02 and 5.01 of these 
documents according to the revision history included there.

 Please apply.

qemu-softfloat-nan2008.diff
Index: qemu-git-trunk/fpu/softfloat-specialize.h
===================================================================
--- qemu-git-trunk.orig/fpu/softfloat-specialize.h      2014-12-08 
22:57:38.000000000 +0000
+++ qemu-git-trunk/fpu/softfloat-specialize.h   2014-12-08 23:24:19.558923071 
+0000
@@ -35,10 +35,16 @@ these four paragraphs for those parts of
 
 =============================================================================*/
 
-#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
-#define SNAN_BIT_IS_ONE                1
+#if defined(TARGET_MIPS)
+/* Has to be decided dynamically.  */
+#define SNAN_BIT_IS_VARIABLE   1
+#define SNAN_BIT_IS_ONE        0
+#elif defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#define SNAN_BIT_IS_VARIABLE   0
+#define SNAN_BIT_IS_ONE        1
 #else
-#define SNAN_BIT_IS_ONE                0
+#define SNAN_BIT_IS_VARIABLE   0
+#define SNAN_BIT_IS_ONE        0
 #endif
 
 #if defined(TARGET_XTENSA)
@@ -55,6 +61,10 @@ inline float16 float16_default_nan(STATU
 {
 #if defined(TARGET_ARM)
     return const_float16(0x7E00);
+#elif SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode)
+           ? const_float16(0x7E00)
+           : const_float16(0x7DFF);
 #elif SNAN_BIT_IS_ONE
     return const_float16(0x7DFF);
 #else
@@ -72,6 +82,10 @@ inline float32 float32_default_nan(STATU
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
       defined(TARGET_XTENSA)
     return const_float32(0x7FC00000);
+#elif SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode)
+           ? const_float32(0x7FC00000)
+           : const_float32(0x7FBFFFFF);
 #elif SNAN_BIT_IS_ONE
     return const_float32(0x7FBFFFFF);
 #else
@@ -88,6 +102,10 @@ inline float64 float64_default_nan(STATU
     return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
     return const_float64(LIT64(0x7FF8000000000000));
+#elif SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode)
+           ? const_float64(LIT64(0x7FF8000000000000))
+           : const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
 #elif SNAN_BIT_IS_ONE
     return const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
 #else
@@ -100,7 +118,11 @@ inline float64 float64_default_nan(STATU
 *----------------------------------------------------------------------------*/
 inline floatx80 floatx80_default_nan(STATUS_PARAM_ONLY)
 {
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode)
+           ? make_floatx80(0xFFFF, LIT64(0xC000000000000000))
+           : make_floatx80(0x7FFF, LIT64(0xBFFFFFFFFFFFFFFF));
+#elif SNAN_BIT_IS_ONE
     return make_floatx80(0x7FFF, LIT64(0xBFFFFFFFFFFFFFFF));
 #else
     return make_floatx80(0xFFFF, LIT64(0xC000000000000000));
@@ -113,7 +135,13 @@ inline floatx80 floatx80_default_nan(STA
 *----------------------------------------------------------------------------*/
 inline float128 float128_default_nan(STATUS_PARAM_ONLY)
 {
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode)
+           ? make_float128(LIT64(0x7FFF800000000000),
+                           LIT64(0x0000000000000000))
+           : make_float128(LIT64(0x7FFF7FFFFFFFFFFF),
+                           LIT64(0xFFFFFFFFFFFFFFFF));
+#elif SNAN_BIT_IS_ONE
     return make_float128(LIT64(0x7FFF7FFFFFFFFFFF), LIT64(0xFFFFFFFFFFFFFFFF));
 #else
     return make_float128(LIT64(0xFFFF800000000000), LIT64(0x0000000000000000));
@@ -162,7 +190,9 @@ int float16_is_quiet_nan(float16 a_ STAT
     int __attribute__ ((unused)) x, y;
     x = (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
     y = (a & ~0x8000) >= 0x7c80;
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -180,7 +210,9 @@ int float16_is_signaling_nan(float16 a_ 
     int __attribute__ ((unused)) x, y;
     x = (a & ~0x8000) >= 0x7c80;
     y = (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -195,8 +227,10 @@ int float16_is_signaling_nan(float16 a_ 
 float16 float16_maybe_silence_nan(float16 a_ STATUS_PARAM)
 {
     if (float16_is_signaling_nan(a_ STATUS_VAR)) {
-#if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#if SNAN_BIT_IS_VARIABLE
+        return float16_default_nan(status);
+#elif SNAN_BIT_IS_ONE
+#  if defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float16_default_nan(status);
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -272,7 +306,9 @@ int float32_is_quiet_nan(float32 a_ STAT
     int __attribute__ ((unused)) x, y;
     x = (((a >> 22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
     y = 0xFF800000 <= (uint32_t) (a << 1);
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -290,7 +326,9 @@ int float32_is_signaling_nan(float32 a_ 
     int __attribute__ ((unused)) x, y;
     x = 0xFF800000 <= (uint32_t) (a << 1);
     y = (((a >> 22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -306,8 +344,10 @@ int float32_is_signaling_nan(float32 a_ 
 float32 float32_maybe_silence_nan(float32 a_ STATUS_PARAM)
 {
     if (float32_is_signaling_nan(a_ STATUS_VAR)) {
-#if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#if SNAN_BIT_IS_VARIABLE
+        return float32_default_nan(status);
+#elif SNAN_BIT_IS_ONE
+#  if defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float32_default_nan(status);
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -688,7 +728,9 @@ int float64_is_quiet_nan(float64 a_ STAT
     int __attribute__ ((unused)) x, y;
     x = (((a >> 51) & 0xFFF) == 0xFFE) && (a & LIT64(0x0007FFFFFFFFFFFF));
     y = LIT64(0xFFF0000000000000) <= (uint64_t) (a << 1);
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -706,7 +748,9 @@ int float64_is_signaling_nan(float64 a_ 
     int __attribute__ ((unused)) x, y;
     x = LIT64(0xFFF0000000000000) <= (uint64_t) (a << 1);
     y = (((a >> 51) & 0xFFF) == 0xFFE) && (a & LIT64(0x0007FFFFFFFFFFFF));
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -722,8 +766,10 @@ int float64_is_signaling_nan(float64 a_ 
 float64 float64_maybe_silence_nan(float64 a_ STATUS_PARAM)
 {
     if (float64_is_signaling_nan(a_ STATUS_VAR)) {
-#if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#if SNAN_BIT_IS_VARIABLE
+        return float64_default_nan(status);
+#elif SNAN_BIT_IS_ONE
+#  if defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         return float64_default_nan(status);
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -896,7 +942,9 @@ int floatx80_is_quiet_nan(floatx80 a STA
          && (a.low == aLow));
     y = (((a.high & 0x7FFF) == 0x7FFF)
          && (LIT64(0x8000000000000000) <= ((uint64_t) (a.low << 1))));
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -919,7 +967,9 @@ int floatx80_is_signaling_nan(floatx80 a
     y = (((a.high & 0x7FFF) == 0x7FFF)
          && (uint64_t) (aLow << 1)
          && (a.low == aLow));
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -935,8 +985,10 @@ int floatx80_is_signaling_nan(floatx80 a
 floatx80 floatx80_maybe_silence_nan(floatx80 a STATUS_PARAM)
 {
     if (floatx80_is_signaling_nan(a STATUS_VAR)) {
-#if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#if SNAN_BIT_IS_VARIABLE
+        a = floatx80_default_nan(status);
+#elif SNAN_BIT_IS_ONE
+#  if defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         a = floatx80_default_nan(status);
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
@@ -1056,7 +1108,9 @@ int float128_is_quiet_nan(float128 a STA
          && (a.low || (a.high & LIT64(0x00007FFFFFFFFFFF))));
     y = ((LIT64(0xFFFE000000000000) <= (uint64_t) (a.high << 1))
          && (a.low || (a.high & LIT64(0x0000FFFFFFFFFFFF))));
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -1075,7 +1129,9 @@ int float128_is_signaling_nan(float128 a
          && (a.low || (a.high & LIT64(0x0000FFFFFFFFFFFF))));
     y = ((((a.high >> 47) & 0xFFFF) == 0xFFFE)
          && (a.low || (a.high & LIT64(0x00007FFFFFFFFFFF))));
-#if SNAN_BIT_IS_ONE
+#if SNAN_BIT_IS_VARIABLE
+    return STATUS(nan2008_mode) ? y : x;
+#elif SNAN_BIT_IS_ONE
     return x;
 #else
     return y;
@@ -1091,8 +1147,10 @@ int float128_is_signaling_nan(float128 a
 float128 float128_maybe_silence_nan(float128 a STATUS_PARAM)
 {
     if (float128_is_signaling_nan(a STATUS_VAR)) {
-#if SNAN_BIT_IS_ONE
-#  if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#if SNAN_BIT_IS_VARIABLE
+        a = float128_default_nan(status);
+#elif SNAN_BIT_IS_ONE
+#  if defined(TARGET_SH4) || defined(TARGET_UNICORE32)
         a = float128_default_nan(status);
 #  else
 #    error Rules for silencing a signaling NaN are target-specific
Index: qemu-git-trunk/include/fpu/softfloat.h
===================================================================
--- qemu-git-trunk.orig/include/fpu/softfloat.h 2014-12-08 22:57:37.000000000 
+0000
+++ qemu-git-trunk/include/fpu/softfloat.h      2014-12-08 22:59:22.897902279 
+0000
@@ -179,6 +179,7 @@ typedef struct float_status {
     /* should denormalised inputs go to zero and set the input_denormal flag? 
*/
     flag flush_inputs_to_zero;
     flag default_nan_mode;
+    flag nan2008_mode;
 } float_status;
 
 static inline void set_float_detect_tininess(int val STATUS_PARAM)
@@ -209,6 +210,10 @@ static inline void set_default_nan_mode(
 {
     STATUS(default_nan_mode) = val;
 }
+static inline void set_nan2008_mode(flag val STATUS_PARAM)
+{
+    STATUS(nan2008_mode) = val;
+}
 static inline int get_float_detect_tininess(float_status *status)
 {
     return STATUS(float_detect_tininess);
Index: qemu-git-trunk/target-mips/cpu.h
===================================================================
--- qemu-git-trunk.orig/target-mips/cpu.h       2014-12-08 22:57:37.000000000 
+0000
+++ qemu-git-trunk/target-mips/cpu.h    2014-12-08 23:22:12.537811707 +0000
@@ -615,7 +615,11 @@ void mips_cpu_list (FILE *f, fprintf_fun
 extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
 extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);
 
-#define CPU_SAVE_VERSION 7
+#define CPU_SAVE_VERSION 8
+/* We preserve compatibility with rev. 7 images.  */
+#define CPU_SAVE_VERSION_OLDEST_SUPPORTED 7
+/* Rev. 8 added 2008 NaN support.  */
+#define CPU_SAVE_VERSION_2008_NAN 8
 
 /* MMU modes definitions. We carefully match the indices with our
    hflags layout. */
Index: qemu-git-trunk/target-mips/machine.c
===================================================================
--- qemu-git-trunk.orig/target-mips/machine.c   2014-12-08 22:57:37.000000000 
+0000
+++ qemu-git-trunk/target-mips/machine.c        2014-12-08 22:59:22.897902279 
+0000
@@ -39,6 +39,7 @@ static void save_fpu(QEMUFile *f, CPUMIP
     for(i = 0; i < 32; i++)
         qemu_put_be64s(f, &fpu->fpr[i].d);
     qemu_put_8s(f, &fpu->fp_status.flush_to_zero);
+    qemu_put_8s(f, &fpu->fp_status.nan2008_mode);
     qemu_put_s8s(f, &fpu->fp_status.float_rounding_mode);
     qemu_put_s8s(f, &fpu->fp_status.float_exception_flags);
     qemu_put_be32s(f, &fpu->fcr0);
@@ -195,13 +196,18 @@ static void load_tc(QEMUFile *f, TCState
     qemu_get_8s(f, &tc->msa_fp_status.flush_inputs_to_zero);
 }
 
-static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu, int version_id)
 {
     int i;
 
     for(i = 0; i < 32; i++)
         qemu_get_be64s(f, &fpu->fpr[i].d);
     qemu_get_8s(f, &fpu->fp_status.flush_to_zero);
+    if (version_id >= CPU_SAVE_VERSION_2008_NAN) {
+        qemu_get_8s(f, &fpu->fp_status.nan2008_mode);
+    } else {
+        fpu->fp_status.nan2008_mode = 0;
+    }
     qemu_get_s8s(f, &fpu->fp_status.float_rounding_mode);
     qemu_get_s8s(f, &fpu->fp_status.float_exception_flags);
     qemu_get_be32s(f, &fpu->fcr0);
@@ -214,7 +220,7 @@ int cpu_load(QEMUFile *f, void *opaque, 
     MIPSCPU *cpu = mips_env_get_cpu(env);
     int i;
 
-    if (version_id != CPU_SAVE_VERSION) {
+    if (version_id < CPU_SAVE_VERSION_OLDEST_SUPPORTED) {
         return -EINVAL;
     }
 
@@ -222,7 +228,7 @@ int cpu_load(QEMUFile *f, void *opaque, 
     load_tc(f, &env->active_tc);
 
     /* Load active FPU */
-    load_fpu(f, &env->active_fpu);
+    load_fpu(f, &env->active_fpu, version_id);
 
     /* Load MVP */
     qemu_get_sbe32s(f, &env->mvp->CP0_MVPControl);
@@ -336,8 +342,9 @@ int cpu_load(QEMUFile *f, void *opaque, 
     for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) {
         load_tc(f, &env->tcs[i]);
     }
-    for (i = 0; i < MIPS_FPU_MAX; i++)
-        load_fpu(f, &env->fpus[i]);
+    for (i = 0; i < MIPS_FPU_MAX; i++) {
+        load_fpu(f, &env->fpus[i], version_id);
+    }
 
     /* XXX: ensure compatibility for halted bit ? */
     tlb_flush(CPU(cpu), 1);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]