From patchwork Wed Jan 12 18:42:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 78608 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3CBCAB6F10 for ; Thu, 13 Jan 2011 05:44:03 +1100 (EST) Received: from localhost ([127.0.0.1]:34089 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pd5fm-0003T8-6C for incoming@patchwork.ozlabs.org; Wed, 12 Jan 2011 13:43:54 -0500 Received: from [140.186.70.92] (port=58048 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pd5es-0003Re-P7 for qemu-devel@nongnu.org; Wed, 12 Jan 2011 13:43:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Pd5em-0000Rh-8t for qemu-devel@nongnu.org; Wed, 12 Jan 2011 13:42:58 -0500 Received: from hall.aurel32.net ([88.191.126.93]:49281) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Pd5el-0000RK-Rk for qemu-devel@nongnu.org; Wed, 12 Jan 2011 13:42:52 -0500 Received: from [2001:470:d4ed:0:5e26:aff:fe2b:6f5b] (helo=volta.aurel32.net) by hall.aurel32.net with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1Pd5ei-0006rP-0d; Wed, 12 Jan 2011 19:42:48 +0100 Received: from aurel32 by volta.aurel32.net with local (Exim 4.72) (envelope-from ) id 1Pd5ej-0005xU-22; Wed, 12 Jan 2011 19:42:49 +0100 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Wed, 12 Jan 2011 19:42:47 +0100 Message-Id: <1294857768-22871-1-git-send-email-aurelien@aurel32.net> X-Mailer: git-send-email 1.7.2.3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: Peter Maydell , Nathan Froyd , Alexander Graf , Aurelien Jarno Subject: [Qemu-devel] [PATCH v2 1/2] target-ppc: fix sNaN propagation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The current FPU code returns 0.0 if one of the operand is a signaling NaN and the VXSNAN exception is disabled. fload_invalid_op_excp() doesn't return a qNaN in case of a VXSNAN exception as the operand should be propagated instead of a new qNaN to be generated. Fix that by calling fload_invalid_op_excp() only for the exception generation (if enabled), and use the softfloat code to correctly compute the result. * v1 -> v2: - fixed a few case were farg.ll was still assigned with the result of fload_invalid_op_excp, spotted by Peter Maydell. Thanks. Cc: Alexander Graf Cc: Peter Maydell Cc: Nathan Froyd Signed-off-by: Aurelien Jarno Reviewed-by: Nathan Froyd --- target-ppc/op_helper.c | 149 +++++++++++++++++++++++++---------------------- 1 files changed, 79 insertions(+), 70 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 9787be7..7ae5052 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -975,15 +975,16 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN addition */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { + if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && + float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN addition */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); } @@ -998,15 +999,16 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN subtraction */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { + if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && + float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN subtraction */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); } @@ -1021,16 +1023,17 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN multiplication */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN multiplication */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + float64_mul(farg1.d, farg2.d, &env->fp_status); } return farg1.ll; @@ -1044,17 +1047,18 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN division */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) { + if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) { /* Division of infinity by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { /* Division of zero by zero */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN division */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } @@ -1232,16 +1236,17 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg2.ll = arg2; farg3.ll = arg3; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1276,16 +1281,17 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg2.ll = arg2; farg3.ll = arg3; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1319,16 +1325,17 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg2.ll = arg2; farg3.ll = arg3; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1364,16 +1371,17 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg2.ll = arg2; farg3.ll = arg3; - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1409,11 +1417,11 @@ uint64_t helper_frsp (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN square root */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else { - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } + f32 = float64_to_float32(farg.d, &env->fp_status); + farg.d = float32_to_float64(f32, &env->fp_status); + return farg.ll; } @@ -1423,13 +1431,14 @@ uint64_t helper_fsqrt (uint64_t arg) CPU_DoubleU farg; farg.ll = arg; - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN square root */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Square root of a negative nonzero number */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); } else { + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } farg.d = float64_sqrt(farg.d, &env->fp_status); } return farg.ll; @@ -1443,10 +1452,9 @@ uint64_t helper_fre (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else { - farg.d = float64_div(float64_one, farg.d, &env->fp_status); + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } + farg.d = float64_div(float64_one, farg.d, &env->fp_status); return farg.d; } @@ -1459,12 +1467,12 @@ uint64_t helper_fres (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else { - farg.d = float64_div(float64_one, farg.d, &env->fp_status); - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } + farg.d = float64_div(float64_one, farg.d, &env->fp_status); + f32 = float64_to_float32(farg.d, &env->fp_status); + farg.d = float32_to_float64(f32, &env->fp_status); + return farg.ll; } @@ -1475,13 +1483,14 @@ uint64_t helper_frsqrte (uint64_t arg) float32 f32; farg.ll = arg; - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN reciprocal square root */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Reciprocal square root of a negative nonzero number */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); } else { + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN reciprocal square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_div(float64_one, farg.d, &env->fp_status); f32 = float64_to_float32(farg.d, &env->fp_status);