[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 8/8] target-arm: Fix VQRSHL Neon instructions (signe
From: |
christophe.lyon |
Subject: |
[Qemu-devel] [PATCH 8/8] target-arm: Fix VQRSHL Neon instructions (signed/unsigned 64 bits and signed 32 bits variants). |
Date: |
Fri, 28 Jan 2011 16:51:06 +0100 |
From: Christophe Lyon <address@hidden>
The addition of the rounding constant could cause overflows.
Signed-off-by: Christophe Lyon <address@hidden>
---
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;
--
1.7.2.3
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., (continued)
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., Alon Levy, 2011/01/31
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., Christophe Lyon, 2011/01/31
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., Aurelien Jarno, 2011/01/31
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., Peter Maydell, 2011/01/31
- Re: [Qemu-devel] [PATCH 1/8] target-arm: Fixes for several shift instructions: VRSHL, VRSHR, VRSHRN, VSHLL, VRSRA., Christophe Lyon, 2011/01/31
[Qemu-devel] [PATCH 4/8] target-arm: fiddle decoding of 64 bit shift by imm and narrow, christophe.lyon, 2011/01/28
[Qemu-devel] [PATCH 3/8] target-arm: VQRSHRN related changes, christophe.lyon, 2011/01/28
[Qemu-devel] [PATCH 5/8] target-arm: fix neon vqrshl instruction, christophe.lyon, 2011/01/28
[Qemu-devel] [PATCH 6/8] target-arm: Fix Neon VQ(R)SHRN instructions., christophe.lyon, 2011/01/28
[Qemu-devel] [PATCH 7/8] implement vsli.64, vsri.64, christophe.lyon, 2011/01/28
[Qemu-devel] [PATCH 8/8] target-arm: Fix VQRSHL Neon instructions (signed/unsigned 64 bits and signed 32 bits variants).,
christophe.lyon <=
[Qemu-devel] [PATCH 2/8] target-arm: Create and use neon_unarrow_sat* helpers, christophe.lyon, 2011/01/28
Re: [Qemu-devel] [PATCH 0/8] target-arm: Fix Neon instructions VQMOVUN VQRSHL VQRSHRN VQRSHRUN VQSHRN VQSHRUN VSLI VSRI, Peter Maydell, 2011/01/28