[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);
- [Qemu-devel] [PATCH 0/7] MIPS: IEEE 754-2008 features support, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 1/7] softfloat: Fix sNaN handling in FP conversion operations, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 2/7] softfloat: Simplify `floatx80ToCommonNaN' function, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 3/7] softfloat: Convert `*_default_nan' variables into inline functions, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 4/7] softfloat: Add SoftFloat status parameter to `*_nan' functions, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 5/7] softfloat: Rework `*_is_*_nan' functions, Maciej W. Rozycki, 2014/12/08
- [Qemu-devel] [PATCH 6/7] softfloat: Add SoftFloat status `nan2008_mode' flag,
Maciej W. Rozycki <=
- [Qemu-devel] [PATCH 7/7] target-mips: Add IEEE 754-2008 features support, Maciej W. Rozycki, 2014/12/08
- Re: [Qemu-devel] [PATCH 0/7] MIPS: IEEE 754-2008 features support, Peter Maydell, 2014/12/09