From patchwork Fri Jan 28 15:51:06 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lyon X-Patchwork-Id: 80867 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BB9871007D5 for ; Sat, 29 Jan 2011 03:03:46 +1100 (EST) Received: from localhost ([127.0.0.1]:52644 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PiqnX-0003UY-SV for incoming@patchwork.ozlabs.org; Fri, 28 Jan 2011 11:03:44 -0500 Received: from [140.186.70.92] (port=48466 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PiqbU-0005Op-VR for qemu-devel@nongnu.org; Fri, 28 Jan 2011 10:51:19 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PiqbS-00010m-P8 for qemu-devel@nongnu.org; Fri, 28 Jan 2011 10:51:16 -0500 Received: from eu1sys200aog108.obsmtp.com ([207.126.144.125]:47997) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PiqbS-00010B-HN for qemu-devel@nongnu.org; Fri, 28 Jan 2011 10:51:14 -0500 Received: from source ([164.129.1.35]) (using TLSv1) by eu1sys200aob108.postini.com ([207.126.147.11]) with SMTP ID DSNKTULl8eSRN2A57Ao3uJc+0fNVG5lSWu0p@postini.com; Fri, 28 Jan 2011 15:51:14 UTC Received: from zeta.dmz-eu.st.com (ns2.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 154ED220 for ; Fri, 28 Jan 2011 15:51:13 +0000 (GMT) Received: from Webmail-eu.st.com (safex1hubcas5.st.com [10.75.90.71]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id EB0312B14 for ; Fri, 28 Jan 2011 15:51:12 +0000 (GMT) Received: from localhost.localdomain (164.129.122.40) by webmail-eu.st.com (10.75.90.13) with Microsoft SMTP Server (TLS) id 8.2.234.1; Fri, 28 Jan 2011 16:51:12 +0100 From: To: Date: Fri, 28 Jan 2011 16:51:06 +0100 Message-ID: <1296229866-32011-9-git-send-email-christophe.lyon@st.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1296229866-32011-1-git-send-email-christophe.lyon@st.com> References: <1296229866-32011-1-git-send-email-christophe.lyon@st.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 207.126.144.125 Subject: [Qemu-devel] [PATCH 8/8] target-arm: Fix VQRSHL Neon instructions (signed/unsigned 64 bits and signed 32 bits variants). X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Christophe Lyon The addition of the rounding constant could cause overflows. Signed-off-by: Christophe Lyon --- target-arm/neon_helper.c | 50 ++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 46 insertions(+), 4 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 3337c52..9faa348 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -847,7 +847,23 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) { int8_t shift = (int8_t)shiftop; if (shift < 0) { - val = (val + (1 << (-1 - shift))) >> -shift; + uint64_t round = (uint64_t)1 << (-1 - shift); + /* Reduce the range as long as the addition overflows. It's + * sufficient to check if (val+round) is < val + * because val and round are > 0. */ + while (((val + round) < val) && round > 1) { + shift++; + round >>= 1; + val >>= 1; + } + if ((val + round) < val) { + /* If addition still overflows at this point, it means + * that round==1, thus shift==-1, and also that + * val==0x&FFFFFFFFFFFFFFF. */ + val = 0x8000000000000000LL; + } else { + val = (val + round) >> -shift; + } } else { \ uint64_t tmp = val; val <<= shift; @@ -859,11 +875,15 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) return val; } +/* The addition of the rounding constant may overflow, so we use an + * intermediate 64 bits accumulator, which is really needed only when + * dealing with 32 bits input values. */ #define NEON_FN(dest, src1, src2) do { \ int8_t tmp; \ tmp = (int8_t)src2; \ if (tmp < 0) { \ - dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \ + int64_t big_dest = ((int64_t)src1 + (1 << (-1 - tmp))); \ + dest = big_dest >> -tmp; \ } else { \ dest = src1 << tmp; \ if ((dest >> tmp) != src1) { \ @@ -876,19 +896,41 @@ NEON_VOP_ENV(qrshl_s16, neon_s16, 2) NEON_VOP_ENV(qrshl_s32, neon_s32, 1) #undef NEON_FN +/* Handling addition overflow with 64 bits inputs values is more + * tricky than with 32 bits values. */ uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) { int8_t shift = (uint8_t)shiftop; int64_t val = valop; if (shift < 0) { - val = (val + (1 << (-1 - shift))) >> -shift; + int64_t round = (int64_t)1 << (-1 - shift); + /* Reduce the range as long as the addition overflows. It's + * sufficient to check if (val+round) is < 0 and val > 0 + * because round is > 0. */ + while ((val > 0) && ((val + round) < 0) && round > 1) { + shift++; + round >>= 1; + val >>= 1; + } + if ((val > 0) && (val + round) < 0) { + /* If addition still overflows at this point, it means + * that round==1, thus shift==-1, and also that + * val==0x7FFFFFFFFFFFFFFF. */ + val = 0x4000000000000000LL; + } else { + val = (val + round) >> -shift; + } } else { int64_t tmp = val; val <<= shift; if ((val >> shift) != tmp) { SET_QC(); - val = tmp >> 31; + if (tmp < 0) { + val = INT64_MIN; + } else { + val = INT64_MAX; + } } } return val;