Patchwork [36/48] target-arm: fix neon vqshl/vqshlu instructions

login
register
mail settings
Submitter Riku Voipio
Date March 26, 2010, 4:06 p.m.
Message ID <29d859fad011536d42ac567ab457ce2ec7f4fdb7.1269617186.git.riku.voipio@nokia.com>
Download mbox | patch
Permalink /patch/48707/
State New
Headers show

Comments

Riku Voipio - March 26, 2010, 4:06 p.m.
From: Juha Riihimäki <juha.riihimaki@nokia.com>

Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
 target-arm/helpers.h     |    4 +++
 target-arm/neon_helper.c |   58 +++++++++++++++++++++++++++++++++++++++++----
 target-arm/translate.c   |   28 +++++++++++-----------
 3 files changed, 70 insertions(+), 20 deletions(-)

Patch

diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index a5fd2e8..e1a8136 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -253,6 +253,10 @@  DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
 DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
 DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
 DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64)
 DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
 DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
 DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 924bf40..7985293 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -600,8 +600,6 @@  uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
         if (val) {
             val = ~(uint64_t)0;
             SET_QC();
-        } else {
-            val = 0;
         }
     } else if (shift <= -64) {
         val = 0;
@@ -622,9 +620,10 @@  uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
     int8_t tmp; \
     tmp = (int8_t)src2; \
     if (tmp >= (ssize_t)sizeof(src1) * 8) { \
-        if (src1) \
+        if (src1) { \
             SET_QC(); \
-        dest = src1 >> 31; \
+        } \
+        dest = src1 ? ((uint32_t)(1 << (sizeof(src1) * 8 - 1)) - (src1 > 0 ? 1 : 0)) : 0; \
     } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
         dest = src1 >> 31; \
     } else if (tmp < 0) { \
@@ -633,7 +632,7 @@  uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
         dest = src1 << tmp; \
         if ((dest >> tmp) != src1) { \
             SET_QC(); \
-            dest = src2 >> 31; \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)) - (src1 > 0 ? 1 : 0); \
         } \
     }} while (0)
 NEON_VOP_ENV(qshl_s8, neon_s8, 4)
@@ -650,7 +649,7 @@  uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
             SET_QC();
             val = (val >> 63) & ~SIGNBIT64;
         }
-    } else if (shift <= 64) {
+    } else if (shift <= -64) {
         val >>= 63;
     } else if (shift < 0) {
         val >>= -shift;
@@ -665,6 +664,53 @@  uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
     return val;
 }
 
+#define NEON_FN(dest, src1, src2) do { \
+    if (src1 & (1 << (sizeof(src1) * 8 - 1))) { \
+        SET_QC(); \
+        dest = 0; \
+    } else { \
+        int8_t tmp; \
+        tmp = (int8_t)src2; \
+        if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+            if (src1) { \
+                SET_QC(); \
+                dest = ~0; \
+            } else { \
+                dest = 0; \
+            } \
+        } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+            dest = 0; \
+        } else if (tmp < 0) { \
+            dest = src1 >> -tmp; \
+        } else { \
+            dest = src1 << tmp; \
+            if ((dest >> tmp) != src1) { \
+                SET_QC(); \
+                dest = ~0; \
+            } \
+        } \
+    }} while (0)
+NEON_VOP_ENV(qshlu_s8, neon_u8, 4)
+NEON_VOP_ENV(qshlu_s16, neon_u16, 2)
+#undef NEON_FN
+
+uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+{
+    if ((int32_t)valop < 0) {
+        SET_QC();
+        return 0;
+    }
+    return helper_neon_qshl_u32(env, valop, shiftop);
+}
+
+uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+    if ((int64_t)valop < 0) {
+        SET_QC();
+        return 0;
+    }
+    return helper_neon_qshl_u64(env, valop, shiftop);
+}
 
 /* FIXME: This is wrong.  */
 #define NEON_FN(dest, src1, src2) do { \
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 26e6bf4..97fac4d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4139,9 +4139,9 @@  static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     case 9: /* VQSHL */
                         if (u) {
                             gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
-                                                     cpu_V0, cpu_V0);
+                                                     cpu_V1, cpu_V0);
                         } else {
-                            gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
+                            gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
                                                      cpu_V1, cpu_V0);
                         }
                         break;
@@ -4612,10 +4612,10 @@  static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                             break;
                         case 6: /* VQSHLU */
-                            gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0,
-                                                     cpu_V1);
+                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, cpu_V0,
+                                                      cpu_V1);
                             break;
-                        case 7: /* VQSHL/VQSHLU */
+                        case 7: /* VQSHL */
                             if (u) {
                                 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
                                                          cpu_V0, cpu_V1);
@@ -4673,26 +4673,26 @@  static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             }
                             break;
                         case 6: /* VQSHLU */
-                            GEN_NEON_INTEGER_OP_ENV(qshl);
-                            break;
-                        case 7: /* VQSHLU */
                             switch (size) {
                             case 0:
-                                gen_helper_neon_qshl_u8(tmp, cpu_env, tmp,
-                                                        tmp2);
+                                gen_helper_neon_qshlu_s8(tmp, cpu_env, tmp,
+                                                         tmp2);
                                 break;
                             case 1:
-                                gen_helper_neon_qshl_u16(tmp, cpu_env, tmp,
-                                                         tmp2);
+                                gen_helper_neon_qshlu_s16(tmp, cpu_env, tmp,
+                                                          tmp2);
                                 break;
                             case 2:
-                                gen_helper_neon_qshl_u32(tmp, cpu_env, tmp,
-                                                         tmp2);
+                                gen_helper_neon_qshlu_s32(tmp, cpu_env, tmp,
+                                                          tmp2);
                                 break;
                             default:
                                 abort(); /* size == 3 is handled earlier */
                             }
                             break;
+                        case 7: /* VQSHL */
+                            GEN_NEON_INTEGER_OP_ENV(qshl);
+                            break;
                         }
                         tcg_temp_free_i32(tmp2);