aboutsummaryrefslogtreecommitdiff
path: root/target-arm/translate.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-04-11 16:26:12 +0100
committerAurelien Jarno <aurelien@aurel32.net>2011-04-12 21:51:51 +0200
commit25f84f79481db5363c638dd95d5c2a0a0e430cee (patch)
tree98932d7614efa11bd6a6dcd6f2adcdbadda6b23a /target-arm/translate.c
parent62698be3bac2e4c969205f3849c48922e0e76e88 (diff)
target-arm: Handle UNDEF cases for Neon 3-regs-same insns
Correct the handling of UNDEF cases for the NEON "3 registers same size" forms, by adding missing checks and rationalising some others so they are done early enough to avoid leaking TCG temporaries. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r--target-arm/translate.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 3fa27e145b..5ffbace5ae 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4348,6 +4348,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if ((neon_3r_sizes[op] & (1 << size)) == 0) {
return 1;
}
+ /* All insns of this form UNDEF for either this condition or the
+ * superset of cases "Q==1"; we catch the latter later.
+ */
+ if (q && ((rd | rn | rm) & 1)) {
+ return 1;
+ }
if (size == 3 && op != NEON_3R_LOGIC) {
/* 64-bit element instructions. */
for (pass = 0; pass < (q ? 2 : 1); pass++) {
@@ -4410,6 +4416,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
return 0;
}
+ pairwise = 0;
switch (op) {
case NEON_3R_VSHL:
case NEON_3R_VQSHL:
@@ -4421,25 +4428,54 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
rtmp = rn;
rn = rm;
rm = rtmp;
- pairwise = 0;
}
break;
+ case NEON_3R_VPADD:
+ if (u) {
+ return 1;
+ }
+ /* Fall through */
case NEON_3R_VPMAX:
case NEON_3R_VPMIN:
- case NEON_3R_VPADD:
pairwise = 1;
break;
- case NEON_3R_FLOAT_ARITH: /* VADD, VSUB, VPADD, VABD (float) */
- pairwise = (u && size < 2);
+ case NEON_3R_FLOAT_ARITH:
+ pairwise = (u && size < 2); /* if VPADD (float) */
+ break;
+ case NEON_3R_FLOAT_MINMAX:
+ pairwise = u; /* if VPMIN/VPMAX (float) */
+ break;
+ case NEON_3R_FLOAT_CMP:
+ if (!u && size) {
+ /* no encoding for U=0 C=1x */
+ return 1;
+ }
+ break;
+ case NEON_3R_FLOAT_ACMP:
+ if (!u) {
+ return 1;
+ }
+ break;
+ case NEON_3R_VRECPS_VRSQRTS:
+ if (u) {
+ return 1;
+ }
break;
- case NEON_3R_FLOAT_MINMAX: /* VPMIN/VPMAX (float) */
- pairwise = u;
+ case NEON_3R_VMUL:
+ if (u && (size != 0)) {
+ /* UNDEF on invalid size for polynomial subcase */
+ return 1;
+ }
break;
default:
- pairwise = 0;
break;
}
+ if (pairwise && q) {
+ /* All the pairwise insns UNDEF if Q is set */
+ return 1;
+ }
+
for (pass = 0; pass < (q ? 4 : 2); pass++) {
if (pairwise) {
@@ -4621,8 +4657,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
break;
case NEON_3R_VPADD:
- if (u)
- return 1;
switch (size) {
case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
@@ -4671,8 +4705,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
break;
case NEON_3R_FLOAT_ACMP:
- if (!u)
- return 1;
if (size == 0)
gen_helper_neon_acge_f32(tmp, tmp, tmp2);
else