From patchwork Wed Aug 17 00:14:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Dutcher X-Patchwork-Id: 659860 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 3sDVDj0nlKz9sRB for ; Wed, 17 Aug 2016 10:17:56 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=andrewdutcher-com.20150623.gappssmtp.com header.i=@andrewdutcher-com.20150623.gappssmtp.com header.b=wZcpH1pm; dkim-atps=neutral Received: from localhost ([::1]:44573 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZoYL-0003ef-5U for incoming@patchwork.ozlabs.org; Tue, 16 Aug 2016 20:17:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55609) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZoXe-0003Nz-El for qemu-devel@nongnu.org; Tue, 16 Aug 2016 20:17:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bZoXa-0001NI-4F for qemu-devel@nongnu.org; Tue, 16 Aug 2016 20:17:09 -0400 Received: from mail-oi0-x230.google.com ([2607:f8b0:4003:c06::230]:34906) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZoXZ-0001NE-U9 for qemu-devel@nongnu.org; Tue, 16 Aug 2016 20:17:06 -0400 Received: by mail-oi0-x230.google.com with SMTP id 4so120535919oih.2 for ; Tue, 16 Aug 2016 17:17:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=andrewdutcher-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=WHApqw6oB3hkzVhwIn6cWiIx2SJnyW9oFwFqySQJFZo=; b=wZcpH1pmGww9r2AtTjryUJ6rd1uv1R+pG4pwcHblZBsChnIQeGIXsWjnYH636Rihe9 PLYofr26FDYtWECidaRT2ivxOR3yQbbXdY5eS7QA4He/YLl7i1HXlLxPhkmdXOTAOr1f rNlni+cjH4d68wKExAsv6xnDNEqi9fOlx4zGXXpf53SgwsnHwHoTM9ayx32h6Fs/mLqM hh/9XyKixTFQBtCChh5V6kFcwmv1EqCRq+CuEOTLFPS4c1irR6+QHOiBRoRBeHcG3BZu KpTvuf3h0gAteWDP2LDvhJqaZIsECHv9zixbcZglc20sbtyIvpZ0dOnupvnjbWd4tpv5 XXyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=WHApqw6oB3hkzVhwIn6cWiIx2SJnyW9oFwFqySQJFZo=; b=U3LIPFvk9gXhhesaLU8SlTvydry/BQWP+A4q9aMkI7plqpwNhn6NFyDbfKeaVPKbKv lfkXO1a3+3RJKCPvSrAQa+vwjfwVHfqaLhgHgFQjmYytdfdobwG5hHxVJW9kEey5wVzV MjgD2elaHuFa8Wui5jsHHHzSPhaNe2f31NUI778R2HjLoA5n7nbYAb9nY0MU2yPyQ4NT /4uYI6fDKrUBjfxRZdDPL5pRzytc96rxlmQqp+kejVchCmhOHConCwRlqMkJQM3VW7K3 dt5eJc/H7ga8hQIcOigNbJAue2GAUj6VQLMl98BQBIHwAiiW/mbdWw8oyxX5imh1zpgQ XfIA== X-Gm-Message-State: AEkoouvW5kBIWVMSUB7OtQ2qG+SItKReAfgZ6OOUFvvmqepOcDOJemn7gEDYjdJTx1/iIQ== X-Received: by 10.157.12.70 with SMTP id 64mr13880555otr.12.1471393024060; Tue, 16 Aug 2016 17:17:04 -0700 (PDT) Received: from localhost.localdomain (ip184-187-188-206.sb.sd.cox.net. [184.187.188.206]) by smtp.gmail.com with ESMTPSA id r38sm14610016ota.22.2016.08.16.17.17.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 16 Aug 2016 17:17:03 -0700 (PDT) From: Andrew Dutcher To: qemu-devel@nongnu.org Date: Tue, 16 Aug 2016 17:14:55 -0700 Message-Id: <1471392895-17324-1-git-send-email-andrew@andrewdutcher.com> X-Mailer: git-send-email 2.7.4 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:4003:c06::230 Subject: [Qemu-devel] [PATCH v5] fpu: add mechanism to check for invalid long double formats X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Andrew Dutcher Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" All operations that take a floatx80 as an operand need to have their inputs checked for malformed encodings. In all of these cases, use the function floatx80_invalid_encoding to perform the check. If an invalid operand is found, raise an invalid operation exception, and then return either NaN (for fp-typed results) or the integer indefinite value (the minimum representable signed integer value, for int-typed results). For the non-quiet comparison operations, this touches adjacent code in order to pass style checks. Signed-off-by: Andrew Dutcher Reviewed-by: Peter Maydell --- Version 5: Add the check to the comparison operations. Touches the NaN check in the non-quiet comparisons because the style checker says I have to. fpu/softfloat.c | 116 +++++++++++++++++++++++++++++++++++++++++------- include/fpu/softfloat.h | 15 +++++++ 2 files changed, 115 insertions(+), 16 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 9b1eccf..8459ca6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -4814,6 +4814,10 @@ int32_t floatx80_to_int32(floatx80 a, float_status *status) int32_t aExp, shiftCount; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return 1 << 31; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4842,6 +4846,10 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status) uint64_t aSig, savedASig; int32_t z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return 1 << 31; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4888,6 +4896,10 @@ int64_t floatx80_to_int64(floatx80 a, float_status *status) int32_t aExp, shiftCount; uint64_t aSig, aSigExtra; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return 1 << 63; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4929,6 +4941,10 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status) uint64_t aSig; int64_t z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return 1 << 63; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4971,6 +4987,10 @@ float32 floatx80_to_float32(floatx80 a, float_status *status) int32_t aExp; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return float32_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4999,6 +5019,10 @@ float64 floatx80_to_float64(floatx80 a, float_status *status) int32_t aExp; uint64_t aSig, zSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return float64_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5027,6 +5051,10 @@ float128 floatx80_to_float128(floatx80 a, float_status *status) int aExp; uint64_t aSig, zSig0, zSig1; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return float128_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5052,6 +5080,10 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) uint64_t lastBitMask, roundBitsMask; floatx80 z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aExp = extractFloatx80Exp( a ); if ( 0x403E <= aExp ) { if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) { @@ -5279,6 +5311,10 @@ floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5300,6 +5336,10 @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5323,6 +5363,10 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status) int32_t aExp, bExp, zExp; uint64_t aSig, bSig, zSig0, zSig1; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5380,6 +5424,10 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) uint64_t aSig, bSig, zSig0, zSig1; uint64_t rem0, rem1, rem2, term0, term1, term2; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5461,6 +5509,10 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) uint64_t aSig0, aSig1, bSig; uint64_t q, term0, term1, alternateASig0, alternateASig1; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5556,6 +5608,10 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status) uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0; uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5620,10 +5676,11 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status) int floatx80_eq(floatx80 a, floatx80 b, float_status *status) { - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise(float_flag_invalid, status); return 0; @@ -5649,10 +5706,11 @@ int floatx80_le(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise(float_flag_invalid, status); return 0; @@ -5682,10 +5740,11 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise(float_flag_invalid, status); return 0; @@ -5712,10 +5771,11 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status) *----------------------------------------------------------------------------*/ int floatx80_unordered(floatx80 a, floatx80 b, float_status *status) { - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise(float_flag_invalid, status); return 1; @@ -5733,6 +5793,10 @@ int floatx80_unordered(floatx80 a, floatx80 b, float_status *status) int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status) { + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5764,6 +5828,10 @@ int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5800,6 +5868,10 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5833,6 +5905,10 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status) *----------------------------------------------------------------------------*/ int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status) { + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return 1; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -7374,6 +7450,10 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b, { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid, status); + return float_relation_unordered; + } if (( ( extractFloatx80Exp( a ) == 0x7fff ) && ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7fff ) && @@ -7645,6 +7725,10 @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) int32_t aExp; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 0e57ee5..c2ef9f2 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -658,6 +658,21 @@ static inline int floatx80_is_any_nan(floatx80 a) return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } +/*---------------------------------------------------------------------------- +| Return whether the given value is an invalid floatx80 encoding. +| Invalid floatx80 encodings arise when the integer bit is not set, but +| the exponent is not zero. The only times the integer bit is permitted to +| be zero is in subnormal numbers and the value zero. +| This includes what the Intel software developer's manual calls pseudo-NaNs, +| pseudo-infinities and un-normal numbers. It does not include +| pseudo-denormals, which must still be correctly handled as inputs even +| if they are never generated as outputs. +*----------------------------------------------------------------------------*/ +static inline bool floatx80_invalid_encoding(floatx80 a) +{ + return (a.low & (1 << 63)) == 0 && (a.high & 0x7FFF) != 0; +} + #define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) #define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) #define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)