target-arm: Use lookup table for size check on Neon 3-reg-same insns
Simplify the checks for invalid size values for the Neon "three registers of the same size" instruction forms (and add them where they were missing) by using a lookup table. This includes adding symbolic constants for the op values in this space, since we now use them in multiple places. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
54f8e61d5b
commit
62698be3ba
@ -3558,15 +3558,14 @@ static void gen_nop_hint(DisasContext *s, int val)
|
||||
|
||||
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
|
||||
|
||||
static inline int gen_neon_add(int size, TCGv t0, TCGv t1)
|
||||
static inline void gen_neon_add(int size, TCGv t0, TCGv t1)
|
||||
{
|
||||
switch (size) {
|
||||
case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
|
||||
case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
|
||||
case 2: tcg_gen_add_i32(t0, t0, t1); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
|
||||
@ -4245,6 +4244,74 @@ static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
|
||||
}
|
||||
}
|
||||
|
||||
/* Symbolic constants for op fields for Neon 3-register same-length.
|
||||
* The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
|
||||
* table A7-9.
|
||||
*/
|
||||
#define NEON_3R_VHADD 0
|
||||
#define NEON_3R_VQADD 1
|
||||
#define NEON_3R_VRHADD 2
|
||||
#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
|
||||
#define NEON_3R_VHSUB 4
|
||||
#define NEON_3R_VQSUB 5
|
||||
#define NEON_3R_VCGT 6
|
||||
#define NEON_3R_VCGE 7
|
||||
#define NEON_3R_VSHL 8
|
||||
#define NEON_3R_VQSHL 9
|
||||
#define NEON_3R_VRSHL 10
|
||||
#define NEON_3R_VQRSHL 11
|
||||
#define NEON_3R_VMAX 12
|
||||
#define NEON_3R_VMIN 13
|
||||
#define NEON_3R_VABD 14
|
||||
#define NEON_3R_VABA 15
|
||||
#define NEON_3R_VADD_VSUB 16
|
||||
#define NEON_3R_VTST_VCEQ 17
|
||||
#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
|
||||
#define NEON_3R_VMUL 19
|
||||
#define NEON_3R_VPMAX 20
|
||||
#define NEON_3R_VPMIN 21
|
||||
#define NEON_3R_VQDMULH_VQRDMULH 22
|
||||
#define NEON_3R_VPADD 23
|
||||
#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
|
||||
#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
|
||||
#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
|
||||
#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
|
||||
#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
|
||||
#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */
|
||||
|
||||
static const uint8_t neon_3r_sizes[] = {
|
||||
[NEON_3R_VHADD] = 0x7,
|
||||
[NEON_3R_VQADD] = 0xf,
|
||||
[NEON_3R_VRHADD] = 0x7,
|
||||
[NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
|
||||
[NEON_3R_VHSUB] = 0x7,
|
||||
[NEON_3R_VQSUB] = 0xf,
|
||||
[NEON_3R_VCGT] = 0x7,
|
||||
[NEON_3R_VCGE] = 0x7,
|
||||
[NEON_3R_VSHL] = 0xf,
|
||||
[NEON_3R_VQSHL] = 0xf,
|
||||
[NEON_3R_VRSHL] = 0xf,
|
||||
[NEON_3R_VQRSHL] = 0xf,
|
||||
[NEON_3R_VMAX] = 0x7,
|
||||
[NEON_3R_VMIN] = 0x7,
|
||||
[NEON_3R_VABD] = 0x7,
|
||||
[NEON_3R_VABA] = 0x7,
|
||||
[NEON_3R_VADD_VSUB] = 0xf,
|
||||
[NEON_3R_VTST_VCEQ] = 0x7,
|
||||
[NEON_3R_VML] = 0x7,
|
||||
[NEON_3R_VMUL] = 0x7,
|
||||
[NEON_3R_VPMAX] = 0x7,
|
||||
[NEON_3R_VPMIN] = 0x7,
|
||||
[NEON_3R_VQDMULH_VQRDMULH] = 0x6,
|
||||
[NEON_3R_VPADD] = 0x7,
|
||||
[NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
|
||||
[NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
|
||||
[NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
|
||||
[NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
|
||||
[NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
|
||||
[NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
|
||||
};
|
||||
|
||||
/* Translate a NEON data processing instruction. Return nonzero if the
|
||||
instruction is invalid.
|
||||
We process data in a mixture of 32-bit and 64-bit chunks.
|
||||
@ -4277,56 +4344,59 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
if ((insn & (1 << 23)) == 0) {
|
||||
/* Three register same length. */
|
||||
op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
|
||||
if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
|
||||
|| op == 10 || op == 11 || op == 16)) {
|
||||
/* 64-bit element instructions. */
|
||||
/* Catch invalid op and bad size combinations: UNDEF */
|
||||
if ((neon_3r_sizes[op] & (1 << size)) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (size == 3 && op != NEON_3R_LOGIC) {
|
||||
/* 64-bit element instructions. */
|
||||
for (pass = 0; pass < (q ? 2 : 1); pass++) {
|
||||
neon_load_reg64(cpu_V0, rn + pass);
|
||||
neon_load_reg64(cpu_V1, rm + pass);
|
||||
switch (op) {
|
||||
case 1: /* VQADD */
|
||||
case NEON_3R_VQADD:
|
||||
if (u) {
|
||||
gen_helper_neon_qadd_u64(cpu_V0, cpu_V0, cpu_V1);
|
||||
} else {
|
||||
gen_helper_neon_qadd_s64(cpu_V0, cpu_V0, cpu_V1);
|
||||
}
|
||||
break;
|
||||
case 5: /* VQSUB */
|
||||
case NEON_3R_VQSUB:
|
||||
if (u) {
|
||||
gen_helper_neon_qsub_u64(cpu_V0, cpu_V0, cpu_V1);
|
||||
} else {
|
||||
gen_helper_neon_qsub_s64(cpu_V0, cpu_V0, cpu_V1);
|
||||
}
|
||||
break;
|
||||
case 8: /* VSHL */
|
||||
case NEON_3R_VSHL:
|
||||
if (u) {
|
||||
gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
|
||||
} else {
|
||||
gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
|
||||
}
|
||||
break;
|
||||
case 9: /* VQSHL */
|
||||
case NEON_3R_VQSHL:
|
||||
if (u) {
|
||||
gen_helper_neon_qshl_u64(cpu_V0, cpu_V1, cpu_V0);
|
||||
} else {
|
||||
gen_helper_neon_qshl_s64(cpu_V0, cpu_V1, cpu_V0);
|
||||
}
|
||||
break;
|
||||
case 10: /* VRSHL */
|
||||
case NEON_3R_VRSHL:
|
||||
if (u) {
|
||||
gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
|
||||
} else {
|
||||
gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
|
||||
}
|
||||
break;
|
||||
case 11: /* VQRSHL */
|
||||
case NEON_3R_VQRSHL:
|
||||
if (u) {
|
||||
gen_helper_neon_qrshl_u64(cpu_V0, cpu_V1, cpu_V0);
|
||||
} else {
|
||||
gen_helper_neon_qrshl_s64(cpu_V0, cpu_V1, cpu_V0);
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
case NEON_3R_VADD_VSUB:
|
||||
if (u) {
|
||||
tcg_gen_sub_i64(CPU_V001);
|
||||
} else {
|
||||
@ -4341,10 +4411,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
return 0;
|
||||
}
|
||||
switch (op) {
|
||||
case 8: /* VSHL */
|
||||
case 9: /* VQSHL */
|
||||
case 10: /* VRSHL */
|
||||
case 11: /* VQRSHL */
|
||||
case NEON_3R_VSHL:
|
||||
case NEON_3R_VQSHL:
|
||||
case NEON_3R_VRSHL:
|
||||
case NEON_3R_VQRSHL:
|
||||
{
|
||||
int rtmp;
|
||||
/* Shift instruction operands are reversed. */
|
||||
@ -4354,15 +4424,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
pairwise = 0;
|
||||
}
|
||||
break;
|
||||
case 20: /* VPMAX */
|
||||
case 21: /* VPMIN */
|
||||
case 23: /* VPADD */
|
||||
case NEON_3R_VPMAX:
|
||||
case NEON_3R_VPMIN:
|
||||
case NEON_3R_VPADD:
|
||||
pairwise = 1;
|
||||
break;
|
||||
case 26: /* VPADD (float) */
|
||||
case NEON_3R_FLOAT_ARITH: /* VADD, VSUB, VPADD, VABD (float) */
|
||||
pairwise = (u && size < 2);
|
||||
break;
|
||||
case 30: /* VPMIN/VPMAX (float) */
|
||||
case NEON_3R_FLOAT_MINMAX: /* VPMIN/VPMAX (float) */
|
||||
pairwise = u;
|
||||
break;
|
||||
default:
|
||||
@ -4391,16 +4461,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
tmp2 = neon_load_reg(rm, pass);
|
||||
}
|
||||
switch (op) {
|
||||
case 0: /* VHADD */
|
||||
case NEON_3R_VHADD:
|
||||
GEN_NEON_INTEGER_OP(hadd);
|
||||
break;
|
||||
case 1: /* VQADD */
|
||||
case NEON_3R_VQADD:
|
||||
GEN_NEON_INTEGER_OP(qadd);
|
||||
break;
|
||||
case 2: /* VRHADD */
|
||||
case NEON_3R_VRHADD:
|
||||
GEN_NEON_INTEGER_OP(rhadd);
|
||||
break;
|
||||
case 3: /* Logic ops. */
|
||||
case NEON_3R_LOGIC: /* Logic ops. */
|
||||
switch ((u << 2) | size) {
|
||||
case 0: /* VAND */
|
||||
tcg_gen_and_i32(tmp, tmp, tmp2);
|
||||
@ -4434,81 +4504,80 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4: /* VHSUB */
|
||||
case NEON_3R_VHSUB:
|
||||
GEN_NEON_INTEGER_OP(hsub);
|
||||
break;
|
||||
case 5: /* VQSUB */
|
||||
case NEON_3R_VQSUB:
|
||||
GEN_NEON_INTEGER_OP(qsub);
|
||||
break;
|
||||
case 6: /* VCGT */
|
||||
case NEON_3R_VCGT:
|
||||
GEN_NEON_INTEGER_OP(cgt);
|
||||
break;
|
||||
case 7: /* VCGE */
|
||||
case NEON_3R_VCGE:
|
||||
GEN_NEON_INTEGER_OP(cge);
|
||||
break;
|
||||
case 8: /* VSHL */
|
||||
case NEON_3R_VSHL:
|
||||
GEN_NEON_INTEGER_OP(shl);
|
||||
break;
|
||||
case 9: /* VQSHL */
|
||||
case NEON_3R_VQSHL:
|
||||
GEN_NEON_INTEGER_OP(qshl);
|
||||
break;
|
||||
case 10: /* VRSHL */
|
||||
case NEON_3R_VRSHL:
|
||||
GEN_NEON_INTEGER_OP(rshl);
|
||||
break;
|
||||
case 11: /* VQRSHL */
|
||||
case NEON_3R_VQRSHL:
|
||||
GEN_NEON_INTEGER_OP(qrshl);
|
||||
break;
|
||||
case 12: /* VMAX */
|
||||
case NEON_3R_VMAX:
|
||||
GEN_NEON_INTEGER_OP(max);
|
||||
break;
|
||||
case 13: /* VMIN */
|
||||
case NEON_3R_VMIN:
|
||||
GEN_NEON_INTEGER_OP(min);
|
||||
break;
|
||||
case 14: /* VABD */
|
||||
case NEON_3R_VABD:
|
||||
GEN_NEON_INTEGER_OP(abd);
|
||||
break;
|
||||
case 15: /* VABA */
|
||||
case NEON_3R_VABA:
|
||||
GEN_NEON_INTEGER_OP(abd);
|
||||
tcg_temp_free_i32(tmp2);
|
||||
tmp2 = neon_load_reg(rd, pass);
|
||||
gen_neon_add(size, tmp, tmp2);
|
||||
break;
|
||||
case 16:
|
||||
case NEON_3R_VADD_VSUB:
|
||||
if (!u) { /* VADD */
|
||||
if (gen_neon_add(size, tmp, tmp2))
|
||||
return 1;
|
||||
gen_neon_add(size, tmp, tmp2);
|
||||
} else { /* VSUB */
|
||||
switch (size) {
|
||||
case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
|
||||
case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
|
||||
case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
case NEON_3R_VTST_VCEQ:
|
||||
if (!u) { /* VTST */
|
||||
switch (size) {
|
||||
case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
|
||||
case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
|
||||
case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
} else { /* VCEQ */
|
||||
switch (size) {
|
||||
case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
|
||||
case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
|
||||
case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 18: /* Multiply. */
|
||||
case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
|
||||
switch (size) {
|
||||
case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
|
||||
case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
|
||||
case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
tcg_temp_free_i32(tmp2);
|
||||
tmp2 = neon_load_reg(rd, pass);
|
||||
@ -4518,7 +4587,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
gen_neon_add(size, tmp, tmp2);
|
||||
}
|
||||
break;
|
||||
case 19: /* VMUL */
|
||||
case NEON_3R_VMUL:
|
||||
if (u) { /* polynomial */
|
||||
gen_helper_neon_mul_p8(tmp, tmp, tmp2);
|
||||
} else { /* Integer */
|
||||
@ -4526,42 +4595,42 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
|
||||
case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
|
||||
case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 20: /* VPMAX */
|
||||
case NEON_3R_VPMAX:
|
||||
GEN_NEON_INTEGER_OP(pmax);
|
||||
break;
|
||||
case 21: /* VPMIN */
|
||||
case NEON_3R_VPMIN:
|
||||
GEN_NEON_INTEGER_OP(pmin);
|
||||
break;
|
||||
case 22: /* Hultiply high. */
|
||||
case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */
|
||||
if (!u) { /* VQDMULH */
|
||||
switch (size) {
|
||||
case 1: gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); break;
|
||||
case 2: gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
} else { /* VQRDHMUL */
|
||||
} else { /* VQRDMULH */
|
||||
switch (size) {
|
||||
case 1: gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); break;
|
||||
case 2: gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 23: /* VPADD */
|
||||
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;
|
||||
case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
|
||||
default: return 1;
|
||||
default: abort();
|
||||
}
|
||||
break;
|
||||
case 26: /* Floating point arithnetic. */
|
||||
case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
|
||||
switch ((u << 2) | size) {
|
||||
case 0: /* VADD */
|
||||
gen_helper_neon_add_f32(tmp, tmp, tmp2);
|
||||
@ -4576,10 +4645,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
gen_helper_neon_abd_f32(tmp, tmp, tmp2);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 27: /* Float multiply. */
|
||||
case NEON_3R_FLOAT_MULTIPLY:
|
||||
gen_helper_neon_mul_f32(tmp, tmp, tmp2);
|
||||
if (!u) {
|
||||
tcg_temp_free_i32(tmp2);
|
||||
@ -4591,7 +4660,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 28: /* Float compare. */
|
||||
case NEON_3R_FLOAT_CMP:
|
||||
if (!u) {
|
||||
gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
|
||||
} else {
|
||||
@ -4601,7 +4670,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
|
||||
}
|
||||
break;
|
||||
case 29: /* Float compare absolute. */
|
||||
case NEON_3R_FLOAT_ACMP:
|
||||
if (!u)
|
||||
return 1;
|
||||
if (size == 0)
|
||||
@ -4609,13 +4678,13 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
else
|
||||
gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
|
||||
break;
|
||||
case 30: /* Float min/max. */
|
||||
case NEON_3R_FLOAT_MINMAX:
|
||||
if (size == 0)
|
||||
gen_helper_neon_max_f32(tmp, tmp, tmp2);
|
||||
else
|
||||
gen_helper_neon_min_f32(tmp, tmp, tmp2);
|
||||
break;
|
||||
case 31:
|
||||
case NEON_3R_VRECPS_VRSQRTS:
|
||||
if (size == 0)
|
||||
gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user