From patchwork Tue Jan 7 16:06:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Musta X-Patchwork-Id: 307710 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 D2BED2C0096 for ; Wed, 8 Jan 2014 03:55:48 +1100 (EST) Received: from localhost ([::1]:41391 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZDj-0007Pv-Vk for incoming@patchwork.ozlabs.org; Tue, 07 Jan 2014 11:09:35 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53579) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZBO-0004Zx-DT for qemu-devel@nongnu.org; Tue, 07 Jan 2014 11:07:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1W0ZBI-0000Zs-BX for qemu-devel@nongnu.org; Tue, 07 Jan 2014 11:07:10 -0500 Received: from mail-oa0-x229.google.com ([2607:f8b0:4003:c02::229]:49047) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZBH-0000Zj-Sb; Tue, 07 Jan 2014 11:07:04 -0500 Received: by mail-oa0-f41.google.com with SMTP id j17so390557oag.0 for ; Tue, 07 Jan 2014 08:07:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=YjWl9oQTo+n1dzZWHj3YOnQ0RAMIcQJhaXAxPOBWUMM=; b=ijRfdfY8vyICqW3D0CU64GSdkbR+uHO1Vtd3IDDLmaLA9Xafu6oRNbSEyxsyLpj2pu YQBKZn3o4xFqqTBG+L0dL63tPxZ9JSTLzWlpKOjRnqD7JBVd+IKIyCICNa6aYdchOg1O mL2Fw2gwnTbHJJCIbiCNRhi5mDcZH2gO2/1KQgQjHskQL0C9EZEoGb7bzUstRzqbiHAo pOY/WGIEfrZ9aZNGbSNxrxuTZ0Gb+qpR8HRkddIeScO5ekaznkLdEplAOkFYoh2/JTe4 dx8gMKnF4ybeJDKkq3PjP/AxQq5TEgDjENJuzL1lJt+1QTrhmOtXF6d5WI4W4WDys1qv LSJg== X-Received: by 10.60.65.5 with SMTP id t5mr77692320oes.19.1389110823451; Tue, 07 Jan 2014 08:07:03 -0800 (PST) Received: from tmusta-sc.rchland.ibm.com (rchp4.rochester.ibm.com. [129.42.161.36]) by mx.google.com with ESMTPSA id z5sm90198346obg.13.2014.01.07.08.07.01 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 07 Jan 2014 08:07:02 -0800 (PST) From: Tom Musta To: qemu-devel@nongnu.org Date: Tue, 7 Jan 2014 10:06:01 -0600 Message-Id: <1389110770-5199-14-git-send-email-tommusta@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1389110770-5199-1-git-send-email-tommusta@gmail.com> References: <1389110770-5199-1-git-send-email-tommusta@gmail.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:4003:c02::229 Cc: Tom Musta , qemu-ppc@nongnu.org, Peter Maydell Subject: [Qemu-devel] [V4 PATCH 13/22] softfloat: Fix exception flag handling for float32_to_float16() 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 From: Peter Maydell Our float32 to float16 conversion routine was generating the correct numerical answers, but not always setting the right set of exception flags. Fix this, mostly by rearranging the code to more closely resemble RoundAndPackFloat*, and in particular: * non-IEEE halfprec always raises Invalid for input NaNs * we need to check for the overflow case before underflow * we weren't getting the tininess-detected-after-rounding case correct (somewhat academic since only ARM uses halfprec and it is always tininess-detected-before-rounding) * non-IEEE halfprec overflow raises only Invalid, not Invalid + Inexact * we weren't setting Inexact when we should Also add some clarifying comments about what the code is doing. Signed-off-by: Peter Maydell Message-Id: <1389013881-15726-2-git-send-email-peter.maydell@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Tom Musta --- fpu/softfloat.c | 105 ++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 66 insertions(+), 39 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 2c598ca..f95c964 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3141,6 +3141,10 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) uint32_t mask; uint32_t increment; int8 roundingMode; + int maxexp = ieee ? 15 : 16; + bool rounding_bumps_exp; + bool is_tiny = false; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); @@ -3149,11 +3153,12 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) if ( aExp == 0xFF ) { if (aSig) { /* Input is a NaN */ - float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); if (!ieee) { + float_raise(float_flag_invalid STATUS_VAR); return packFloat16(aSign, 0, 0); } - return r; + return commonNaNToFloat16( + float32ToCommonNaN(a STATUS_VAR) STATUS_VAR); } /* Infinity */ if (!ieee) { @@ -3165,58 +3170,80 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) if (aExp == 0 && aSig == 0) { return packFloat16(aSign, 0, 0); } - /* Decimal point between bits 22 and 23. */ + /* Decimal point between bits 22 and 23. Note that we add the 1 bit + * even if the input is denormal; however this is harmless because + * the largest possible single-precision denormal is still smaller + * than the smallest representable half-precision denormal, and so we + * will end up ignoring aSig and returning via the "always return zero" + * codepath. + */ aSig |= 0x00800000; aExp -= 0x7f; + /* Calculate the mask of bits of the mantissa which are not + * representable in half-precision and will be lost. + */ if (aExp < -14) { + /* Will be denormal in halfprec */ mask = 0x00ffffff; if (aExp >= -24) { mask >>= 25 + aExp; } } else { + /* Normal number in halfprec */ mask = 0x00001fff; } - if (aSig & mask) { - float_raise( float_flag_underflow STATUS_VAR ); - roundingMode = STATUS(float_rounding_mode); - switch (roundingMode) { - case float_round_nearest_even: - increment = (mask + 1) >> 1; - if ((aSig & mask) == increment) { - increment = aSig & (increment << 1); - } - break; - case float_round_up: - increment = aSign ? 0 : mask; - break; - case float_round_down: - increment = aSign ? mask : 0; - break; - default: /* round_to_zero */ - increment = 0; - break; - } - aSig += increment; - if (aSig >= 0x01000000) { - aSig >>= 1; - aExp++; - } - } else if (aExp < -14 - && STATUS(float_detect_tininess) == float_tininess_before_rounding) { - float_raise( float_flag_underflow STATUS_VAR); - } - if (ieee) { - if (aExp > 15) { - float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + roundingMode = STATUS(float_rounding_mode); + switch (roundingMode) { + case float_round_nearest_even: + increment = (mask + 1) >> 1; + if ((aSig & mask) == increment) { + increment = aSig & (increment << 1); + } + break; + case float_round_up: + increment = aSign ? 0 : mask; + break; + case float_round_down: + increment = aSign ? mask : 0; + break; + default: /* round_to_zero */ + increment = 0; + break; + } + + rounding_bumps_exp = (aSig + increment >= 0x01000000); + + if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { + if (ieee) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); return packFloat16(aSign, 0x1f, 0); - } - } else { - if (aExp > 16) { - float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR); + } else { + float_raise(float_flag_invalid STATUS_VAR); return packFloat16(aSign, 0x1f, 0x3ff); } } + + if (aExp < -14) { + /* Note that flush-to-zero does not affect half-precision results */ + is_tiny = + (STATUS(float_detect_tininess) == float_tininess_before_rounding) + || (aExp < -15) + || (!rounding_bumps_exp); + } + if (aSig & mask) { + float_raise(float_flag_inexact STATUS_VAR); + if (is_tiny) { + float_raise(float_flag_underflow STATUS_VAR); + } + } + + aSig += increment; + if (rounding_bumps_exp) { + aSig >>= 1; + aExp++; + } + if (aExp < -24) { return packFloat16(aSign, 0, 0); }