From patchwork Sun Dec 29 22:09:59 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 22777 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ig0-f199.google.com (mail-ig0-f199.google.com [209.85.213.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id A30A223FDF for ; Sun, 29 Dec 2013 22:10:20 +0000 (UTC) Received: by mail-ig0-f199.google.com with SMTP id hk11sf47960741igb.2 for ; Sun, 29 Dec 2013 14:10:19 -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:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=V9zL0sNDASRjxgkyYwVTZ9mXl+l/I4W74ss7wf66zbY=; b=GIrJeM1B9yuJzZADFaFOOy/lYtH1+Ng/Uz1pLxwyilPn6185u/wJWbBXfU31/xaGrh GVccSRN0I2ksVuFXErEbYUYfVW0Gd4f32FKulpJVEs2lyhapSbyXxtO2MqfDvQwboETv 9h8O5gIfrz+3RzjnurFgEh4T81sbT1MAG3PeTZae+Smu5i3j/u0iAOgG2gZn/63+JJXa TFRXm69RlBhzcwjzrmc5A4IqBVbmSozk4N3qB1G4LCC6mz5UkOg9CWAqUyJVRVXz82B6 Pejbry9GjtH/f2mCsWXDau6yy8X8pkyoTNqsY2aXnhGYiNu2YS/emuHSb2+kV8K26wPi 2biQ== X-Gm-Message-State: ALoCoQmO784fjpQsnVFEYfTjUU/FuhmdxuGODRgOviX/lFUjbTt/xbeB2kHsUrtgG2TY6yjHKzeK X-Received: by 10.182.29.196 with SMTP id m4mr17781227obh.26.1388355019536; Sun, 29 Dec 2013 14:10:19 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.128.41 with SMTP id nl9ls3406682qeb.56.gmail; Sun, 29 Dec 2013 14:10:19 -0800 (PST) X-Received: by 10.220.90.83 with SMTP id h19mr90759vcm.39.1388355019397; Sun, 29 Dec 2013 14:10:19 -0800 (PST) Received: from mail-vb0-f42.google.com (mail-vb0-f42.google.com [209.85.212.42]) by mx.google.com with ESMTPS id qj10si8395457vcb.144.2013.12.29.14.10.19 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 29 Dec 2013 14:10:19 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.42 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.42; Received: by mail-vb0-f42.google.com with SMTP id w5so5613139vbf.29 for ; Sun, 29 Dec 2013 14:10:19 -0800 (PST) X-Received: by 10.52.113.97 with SMTP id ix1mr28290236vdb.9.1388355019265; Sun, 29 Dec 2013 14:10:19 -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 ey3csp574709ved; Sun, 29 Dec 2013 14:10:18 -0800 (PST) X-Received: by 10.180.12.146 with SMTP id y18mr42054002wib.37.1388355018208; Sun, 29 Dec 2013 14:10:18 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id b19si16884277wiw.77.2013.12.29.14.10.16 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Sun, 29 Dec 2013 14:10:18 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1VxOYZ-0000FM-QN; Sun, 29 Dec 2013 22:09:59 +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 Subject: [PATCH] softfloat: Fix exception flag handling for float32_to_float16() Date: Sun, 29 Dec 2013 22:09:59 +0000 Message-Id: <1388354999-923-1-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 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.42 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: , 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 --- I've had the "fpscr exception flags wrong for halfprec VCVT for 32-bit ARM" bug on my list for years, and finally got round to tackling it, since I'd rather not copy a buggy function when implementing float64_to_float16 for A64... fpu/softfloat.c | 105 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index dbda61b..6a6b656 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3046,6 +3046,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 ); @@ -3054,11 +3058,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) { @@ -3070,58 +3075,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); }