From patchwork Tue Oct 29 13:03:38 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Musta X-Patchwork-Id: 286835 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)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id F2F2B2C037F for ; Wed, 30 Oct 2013 00:04:20 +1100 (EST) Received: from localhost ([::1]:47001 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vb8xz-0000N5-HF for incoming@patchwork.ozlabs.org; Tue, 29 Oct 2013 09:04:15 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48652) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vb8xb-0000Mw-Ru for qemu-devel@nongnu.org; Tue, 29 Oct 2013 09:04:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Vb8xT-0004ia-DM for qemu-devel@nongnu.org; Tue, 29 Oct 2013 09:03:51 -0400 Received: from mail-yh0-x230.google.com ([2607:f8b0:4002:c01::230]:58124) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vb8xT-0004iV-7F; Tue, 29 Oct 2013 09:03:43 -0400 Received: by mail-yh0-f48.google.com with SMTP id f64so3386005yha.7 for ; Tue, 29 Oct 2013 06:03:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=pa8fgnfYoHMONRYRuHm6a06qZaRVrdrgqkTeVmPC8bE=; b=wUXE/sVKLrOeYpVsd0k/O5iKpSU6pAmvlWE29/3MiY1CV9QH/MuxxAwkMAJ1fNKppe P38F5GPzSiojXnRY6alUlcma+0lljmGGuZsSfiMClHAdYTh531W8wdlHs7hpzU8kOHt3 3HSsgAGEQsFAtJXouSAZPhYLTFKfjVKGdzvUfPW0JrHov2ICyt0kek5KvEFuupVP5mBx L0eulCNR2bOKyJK3XEqzrBrQ/wjao6Xl4G7QiyGtdOPXp1t1yi+qXmNxyPfPi5ZxGaOt bX2oaNs11gwt/TBmyRUj0BKzg366qB2Hz1gwTP0cvr7UHJhdlYcRhnXnz7J4P0Ab9bxj Q4gA== X-Received: by 10.236.86.236 with SMTP id w72mr3195yhe.207.1383051822586; Tue, 29 Oct 2013 06:03:42 -0700 (PDT) Received: from [9.10.80.165] (rchp4.rochester.ibm.com. [129.42.161.36]) by mx.google.com with ESMTPSA id v45sm39752472yha.2.2013.10.29.06.03.41 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 29 Oct 2013 06:03:42 -0700 (PDT) Message-ID: <526FB22A.4040209@gmail.com> Date: Tue, 29 Oct 2013 08:03:38 -0500 From: Tom Musta User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.0.1 MIME-Version: 1.0 To: Tom Musta , QEMU Developers References: <526FB1A7.5090109@gmail.com> In-Reply-To: <526FB1A7.5090109@gmail.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:4002:c01::230 Cc: "qemu-ppc@nongnu.org" Subject: [Qemu-devel] [PATCH V2 01/19] Fix float64_to_uint64 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 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. Signed-off-by: Tom Musta --- fpu/softfloat.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 87 insertions(+), 8 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 7ba51b6..3070eaa 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -204,6 +204,47 @@ 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(uint64_t absZ0, uint64_t absZ1 STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven, increment; + int64_t z; + + 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 { + 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); + } + z = absZ0; + if (absZ1) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return z; +} + +/*---------------------------------------------------------------------------- | Returns the fraction bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ @@ -6536,18 +6577,56 @@ 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) { + if (aExp) { + float_raise(float_flag_invalid STATUS_VAR); + } else if (aSig) { /* negative denormalized */ + float_raise(float_flag_inexact STATUS_VAR); + } + return 0; + } + if (aExp) { + aSig |= LIT64(0x0010000000000000); + } + shiftCount = 0x433 - aExp; + if (shiftCount <= 0) { + if (0x43E < aExp) { + if ((aSig != LIT64(0x0010000000000000)) || + (aExp == 0x7FF)) { + float_raise(float_flag_invalid STATUS_VAR); + } + return LIT64(0xFFFFFFFFFFFFFFFF); + } + aSigExtra = 0; + aSig <<= -shiftCount; + } else { + shift64ExtraRightJamming(aSig, 0, shiftCount, &aSig, &aSigExtra); + } + return roundAndPackUint64(aSig, aSigExtra STATUS_VAR); } + uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) { int64_t v;