From patchwork Tue Dec 9 01:55:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 418933 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 95D891400D5 for ; Tue, 9 Dec 2014 12:58:22 +1100 (AEDT) Received: from localhost ([::1]:37317 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XyA4C-0004AA-RD for incoming@patchwork.ozlabs.org; Mon, 08 Dec 2014 20:58:20 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48063) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XyA25-0000pL-2k for qemu-devel@nongnu.org; Mon, 08 Dec 2014 20:56:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XyA1y-00052R-6T for qemu-devel@nongnu.org; Mon, 08 Dec 2014 20:56:09 -0500 Received: from relay1.mentorg.com ([192.94.38.131]:48517) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XyA1x-00052K-Rv for qemu-devel@nongnu.org; Mon, 08 Dec 2014 20:56:02 -0500 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=SVR-IES-FEM-03.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1XyA1w-0000iF-OP from Maciej_Rozycki@mentor.com ; Mon, 08 Dec 2014 17:56:01 -0800 Received: from localhost (137.202.0.76) by SVR-IES-FEM-03.mgc.mentorg.com (137.202.0.108) with Microsoft SMTP Server (TLS) id 14.3.181.6; Tue, 9 Dec 2014 01:55:58 +0000 Date: Tue, 9 Dec 2014 01:55:54 +0000 From: "Maciej W. Rozycki" To: In-Reply-To: Message-ID: References: User-Agent: Alpine 1.10 (DEB 962 2008-03-14) MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Windows NT kernel [generic] [fuzzy] X-Received-From: 192.94.38.131 Cc: Leon Alrae , Thomas Schwinge , Aurelien Jarno Subject: [Qemu-devel] [PATCH 6/7] softfloat: Add SoftFloat status `nan2008_mode' flag X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Signed-off-by: Maciej W. Rozycki --- 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);