mirror of https://gitee.com/openkylin/qemu.git
target/arm: Use gvec for NEON VDUP
Also introduces neon_element_offset to find the env offset of a specific element within a neon register. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20181011205206.3552-7-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
308e563615
commit
32f91fb71f
|
@ -1585,6 +1585,25 @@ neon_reg_offset (int reg, int n)
|
|||
return vfp_reg_offset(0, sreg);
|
||||
}
|
||||
|
||||
/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
|
||||
* where 0 is the least significant end of the register.
|
||||
*/
|
||||
static inline long
|
||||
neon_element_offset(int reg, int element, TCGMemOp size)
|
||||
{
|
||||
int element_size = 1 << size;
|
||||
int ofs = element * element_size;
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
/* Calculate the offset assuming fully little-endian,
|
||||
* then XOR to account for the order of the 8-byte units.
|
||||
*/
|
||||
if (element_size < 8) {
|
||||
ofs ^= 8 - element_size;
|
||||
}
|
||||
#endif
|
||||
return neon_reg_offset(reg, 0) + ofs;
|
||||
}
|
||||
|
||||
static TCGv_i32 neon_load_reg(int reg, int pass)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
|
@ -3432,17 +3451,10 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
|
|||
tmp = load_reg(s, rd);
|
||||
if (insn & (1 << 23)) {
|
||||
/* VDUP */
|
||||
if (size == 0) {
|
||||
gen_neon_dup_u8(tmp, 0);
|
||||
} else if (size == 1) {
|
||||
gen_neon_dup_low16(tmp);
|
||||
}
|
||||
for (n = 0; n <= pass * 2; n++) {
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
tcg_gen_mov_i32(tmp2, tmp);
|
||||
neon_store_reg(rn, n, tmp2);
|
||||
}
|
||||
neon_store_reg(rn, n, tmp);
|
||||
int vec_size = pass ? 16 : 8;
|
||||
tcg_gen_gvec_dup_i32(size, neon_reg_offset(rn, 0),
|
||||
vec_size, vec_size, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
} else {
|
||||
/* VMOV */
|
||||
switch (size) {
|
||||
|
@ -7755,28 +7767,25 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tmp);
|
||||
} else if ((insn & 0x380) == 0) {
|
||||
/* VDUP */
|
||||
int element;
|
||||
TCGMemOp size;
|
||||
|
||||
if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
|
||||
return 1;
|
||||
}
|
||||
if (insn & (1 << 19)) {
|
||||
tmp = neon_load_reg(rm, 1);
|
||||
} else {
|
||||
tmp = neon_load_reg(rm, 0);
|
||||
}
|
||||
if (insn & (1 << 16)) {
|
||||
gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
|
||||
size = MO_8;
|
||||
element = (insn >> 17) & 7;
|
||||
} else if (insn & (1 << 17)) {
|
||||
if ((insn >> 18) & 1)
|
||||
gen_neon_dup_high16(tmp);
|
||||
else
|
||||
gen_neon_dup_low16(tmp);
|
||||
size = MO_16;
|
||||
element = (insn >> 18) & 3;
|
||||
} else {
|
||||
size = MO_32;
|
||||
element = (insn >> 19) & 1;
|
||||
}
|
||||
for (pass = 0; pass < (q ? 4 : 2); pass++) {
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
tcg_gen_mov_i32(tmp2, tmp);
|
||||
neon_store_reg(rd, pass, tmp2);
|
||||
}
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_gvec_dup_mem(size, neon_reg_offset(rd, 0),
|
||||
neon_element_offset(rm, element, size),
|
||||
q ? 16 : 8, q ? 16 : 8);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue