From patchwork Tue Dec 31 13:35:40 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 22832 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pd0-f200.google.com (mail-pd0-f200.google.com [209.85.192.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0B179218CC for ; Tue, 31 Dec 2013 13:36:15 +0000 (UTC) Received: by mail-pd0-f200.google.com with SMTP id p10sf37375729pdj.7 for ; Tue, 31 Dec 2013 05:36:15 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=4h84ICIKE2wfkD7qqwzh1/XB5FYeayiCiyU1QkXZts8=; b=OLT9KxbxYqEZ+sLrW41sXMZhZ83U2wz6cLzGakBXwdBPzNNzrSZQInaK7OeMUt1cDg dVZSD1F6xzKf3Yb4GkfX0jN3FiEIGRGyx5WTlO70eKtWsToErZKLAdmlgsCpPdebQoER O/4c+RdAiJrwPR9Zva7HHjcILlaZWZJ4YK9aWC6Txus6YxG0sPPFR+RvIzQxRXbXo7M/ t3hsqfYHpRaHzilP/MuzSvEQiXgu6VCAv/9zly36PcrJVnd3J+jQl3cWpyya4wrclm3C IbbYflc3wZ0U1co9/6EAZByX8P3VCVQG7jBHBR/vcy4QaaKCm3BZO6OyitfmIacUujUx p41w== X-Gm-Message-State: ALoCoQn4JT9EEmAKvNDxy4584b5Yg8g5HEd+Jp1nTIMti9fCczie8/yF2hvnVVlJXWWOpO6I+SGz X-Received: by 10.66.118.37 with SMTP id kj5mr28867642pab.17.1388496975305; Tue, 31 Dec 2013 05:36:15 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.60.228 with SMTP id k4ls3861531qer.93.gmail; Tue, 31 Dec 2013 05:36:15 -0800 (PST) X-Received: by 10.53.13.44 with SMTP id ev12mr33434379vdd.17.1388496975189; Tue, 31 Dec 2013 05:36:15 -0800 (PST) Received: from mail-vb0-f51.google.com (mail-vb0-f51.google.com [209.85.212.51]) by mx.google.com with ESMTPS id xn8si19063522vdc.22.2013.12.31.05.36.15 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 31 Dec 2013 05:36:15 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.51 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.51; Received: by mail-vb0-f51.google.com with SMTP id 11so6128582vbe.24 for ; Tue, 31 Dec 2013 05:36:15 -0800 (PST) X-Received: by 10.52.114.99 with SMTP id jf3mr172291vdb.66.1388496975019; Tue, 31 Dec 2013 05:36:15 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.59.13.131 with SMTP id ey3csp664813ved; Tue, 31 Dec 2013 05:36:14 -0800 (PST) X-Received: by 10.204.103.7 with SMTP id i7mr23798632bko.14.1388496970891; Tue, 31 Dec 2013 05:36:10 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id dg6si15767399bkc.154.2013.12.31.05.36.08 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 31 Dec 2013 05:36:10 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::1 as permitted sender) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1VxzUE-0000vt-Ez; Tue, 31 Dec 2013 13:35:58 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Alexander Graf , Michael Matz , Claudio Fontana , Dirk Mueller , Laurent Desnogues , kvmarm@lists.cs.columbia.edu, Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Christoffer Dall , Will Newton , Peter Crosthwaite , Tom Musta , Aurelien Jarno Subject: [PATCH 04/22] softfloat: Fix float64_to_uint64 Date: Tue, 31 Dec 2013 13:35:40 +0000 Message-Id: <1388496958-3542-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1388496958-3542-1-git-send-email-peter.maydell@linaro.org> References: <1388496958-3542-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.51 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Tom Musta The comment preceding the float64_to_uint64 routine suggests that the implementation is broken. And this is, indeed, the case. This patch properly implements the conversion of a 64-bit floating point number to an unsigned, 64 bit integer. This contribution can be licensed under either the softfloat-2a or -2b license. V2: Added softfloat license statement. V3: Modified to meet QEMU coding conventions. V4: Fixed incorrect handling of small negatives, which, if rounded up to zero should not set the inexact flag. Signed-off-by: Tom Musta Message-id: 1387397961-4894-2-git-send-email-tommusta@gmail.com PMM notes: this looks like it gives the wrong answer for NaNs with the sign bit set. --- fpu/softfloat.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e078539..afabb04 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -161,7 +161,6 @@ static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM) | exception is raised and the largest positive or negative integer is | returned. *----------------------------------------------------------------------------*/ - static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATUS_PARAM) { int8 roundingMode; @@ -204,6 +203,56 @@ static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATU } /*---------------------------------------------------------------------------- +| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and +| `absZ1', with binary point between bits 63 and 64 (between the input words), +| and returns the properly rounded 64-bit unsigned integer corresponding to the +| input. Ordinarily, the fixed-point input is simply rounded to an integer, +| with the inexact exception raised if the input cannot be represented exactly +| as an integer. However, if the fixed-point input is too large, the invalid +| exception is raised and the largest unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +static int64 roundAndPackUint64(flag zSign, uint64_t absZ0, + uint64_t absZ1 STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven, increment; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = (roundingMode == float_round_nearest_even); + increment = ((int64_t)absZ1 < 0); + if (!roundNearestEven) { + if (roundingMode == float_round_to_zero) { + increment = 0; + } else if (absZ1) { + if (zSign) { + increment = (roundingMode == float_round_down) && absZ1; + } else { + increment = (roundingMode == float_round_up) && absZ1; + } + } + } + if (increment) { + ++absZ0; + if (absZ0 == 0) { + float_raise(float_flag_invalid STATUS_VAR); + return LIT64(0xFFFFFFFFFFFFFFFF); + } + absZ0 &= ~(((uint64_t)(absZ1<<1) == 0) & roundNearestEven); + } + + if (zSign && absZ0) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + + if (absZ1) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return absZ0; +} + +/*---------------------------------------------------------------------------- | Returns the fraction bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ @@ -6643,18 +6692,49 @@ uint_fast16_t float64_to_uint16_round_to_zero(float64 a STATUS_PARAM) return res; } -/* FIXME: This looks broken. */ -uint64_t float64_to_uint64 (float64 a STATUS_PARAM) -{ - int64_t v; +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 64-bit unsigned integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. If the conversion overflows, the +| largest unsigned integer is returned. If 'a' is negative, zero is +| returned. +*----------------------------------------------------------------------------*/ - v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); - v += float64_val(a); - v = float64_to_int64(make_float64(v) STATUS_VAR); +uint64_t float64_to_uint64(float64 a STATUS_PARAM) +{ + flag aSign; + int_fast16_t aExp, shiftCount; + uint64_t aSig, aSigExtra; + a = float64_squash_input_denormal(a STATUS_VAR); - return v - INT64_MIN; + aSig = extractFloat64Frac(a); + aExp = extractFloat64Exp(a); + aSign = extractFloat64Sign(a); + if (aSign && (aExp > 1022)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + if (aExp) { + aSig |= LIT64(0x0010000000000000); + } + shiftCount = 0x433 - aExp; + if (shiftCount <= 0) { + if (0x43E < aExp) { + float_raise(float_flag_invalid STATUS_VAR); + return LIT64(0xFFFFFFFFFFFFFFFF); + } + aSigExtra = 0; + aSig <<= -shiftCount; + } else { + shift64ExtraRightJamming(aSig, 0, shiftCount, &aSig, &aSigExtra); + } + return roundAndPackUint64(aSign, aSig, aSigExtra STATUS_VAR); } + uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) { int64_t v;