From nobody Mon Feb 9 09:00:55 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gentoo.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1553379931024101.07598400311224; Sat, 23 Mar 2019 15:25:31 -0700 (PDT) Received: from localhost ([127.0.0.1]:48805 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h7p4x-0004dw-K3 for importer@patchew.org; Sat, 23 Mar 2019 18:25:27 -0400 Received: from eggs.gnu.org ([209.51.188.92]:49894) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h7p43-0004Ev-IR for qemu-devel@nongnu.org; Sat, 23 Mar 2019 18:24:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h7p42-000578-Dy for qemu-devel@nongnu.org; Sat, 23 Mar 2019 18:24:31 -0400 Received: from mail.gentoo.org ([2001:470:ea4a:1:5054:ff:fec7:86e4]:43481 helo=smtp.gentoo.org) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h7p42-00056N-55; Sat, 23 Mar 2019 18:24:30 -0400 Received: from sf.home (host86-155-197-2.range86-155.btcentralplus.com [86.155.197.2]) (using TLSv1 with cipher ECDHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: slyfox) by smtp.gentoo.org (Postfix) with ESMTPSA id DF872335D03; Sat, 23 Mar 2019 22:24:26 +0000 (UTC) Received: by sf.home (Postfix, from userid 1000) id 02BF823D4E593; Sat, 23 Mar 2019 22:24:21 +0000 (GMT) From: Sergei Trofimovich To: qemu-devel@nongnu.org Date: Sat, 23 Mar 2019 22:24:11 +0000 Message-Id: <20190323222412.9825-1-slyfox@gentoo.org> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:470:ea4a:1:5054:ff:fec7:86e4 Subject: [Qemu-devel] [PATCH] powerpc: fix denorm float->double conversion 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: qemu-ppc@nongnu.org, Richard Henderson , Sergei Trofimovich , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" The bug is initially discovered in GHC test suite. Here is minimal reproduc= er: ```c int main() { volatile float f; volatile double d; *(volatile uint32_t*)&f =3D 0xc0de; d =3D f; printf("f =3D %#x\n", *(volatile uint32_t*)&f); printf("d =3D %#llx (expect 0x37981bc000000000)\n", *(volatile uint64_t*)&d); printf("d =3D %e\n", d); f =3D d; printf("f =3D %#x\n", *(volatile uint32_t*)&f); } ``` ``` $ powerpc-unknown-linux-gnu-gcc -O2 a.c -Wall -o a \ -fno-strict-aliasing -static && qemu-ppc ./a f =3D 0xc0de d =3D 0x37a00000000c0de0 (expect 0x37981bc000000000) d =3D 9.183550e-41 f =3D 0x10000 ``` Here denormalization conversion has a few bugs: - significand (abs_arg) has 32-bit unsigned wraparound in ret |=3D abs_arg << (shift + 29); - significand does not drop explicit leading '1' in denorm 'float' when converting to normalized 'double' - significand had an off-by-one shift CC: Richard Henderson CC: David Gibson CC: qemu-ppc@nongnu.org CC: qemu-devel@nongnu.org Bug: https://bugs.launchpad.net/qemu/+bug/1821444 Signed-off-by: Sergei Trofimovich --- target/ppc/fpu_helper.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 2ed4f42275..1e8b014890 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -64,13 +64,35 @@ uint64_t helper_todouble(uint32_t arg) ret |=3D (uint64_t)extract32(arg, 0, 30) << 29; } else { /* Zero or Denormalized operand. */ - ret =3D (uint64_t)extract32(arg, 31, 1) << 63; + + /* + * Conversion mechanics: + * float denorm (2^(-126) - biased): + * [ sign (1 bit) | exp32 (8 bits) | sign32 (23 bits) ] + * s 0 0001abc...def + * double norm (2^(-1023) - biased): + * [ sign (1 bit) | exp64 (11 bits) | sign64 (52 bits) ] + * s exp abc...def 00..0 + * Thus we are performing the following conversion steps: + * 1. preserve the sign + * 2. normalize denorm sign32: + * 2a. drop explicit leading '1' as normalized numbers + * don't contain it + * 2b. calculate the bit-shift needed to match implicit '1' + * 3. calculate 'exp64' as bias delta plus denorm offset + * 4. put calculated 'sign64' into new location + */ + ret =3D (uint64_t)extract32(arg, 31, 1) << 63; /* [1.] */ if (unlikely(abs_arg !=3D 0)) { /* Denormalized operand. */ - int shift =3D clz32(abs_arg) - 9; - int exp =3D -126 - shift + 1023; - ret |=3D (uint64_t)exp << 52; - ret |=3D abs_arg << (shift + 29); + int lz =3D clz32(abs_arg); + abs_arg &=3D ~(1 << (31 - lz)); /* [2a.] */ + + /* shift within sign32 includeing leading '1' */ + int shift =3D lz + 1 - (32 - 23); + int exp =3D -126 + 1023 - shift; /* [2b]. */ + ret |=3D (uint64_t)exp << 52; /* [3.] */ + ret |=3D (uint64_t)abs_arg << (52 - 23 + shift); /* [4.] */ } } return ret; --=20 2.21.0