Skip to content

Commit

Permalink
target/arm: Use gvec for NEON VDUP
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
rth7680 authored and pm215 committed Oct 24, 2018
1 parent 308e563 commit 32f91fb
Showing 1 changed file with 36 additions and 27 deletions.
63 changes: 36 additions & 27 deletions target/arm/translate.c
Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
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);
size = MO_16;
element = (insn >> 18) & 3;
} else {
size = MO_32;
element = (insn >> 19) & 1;
}
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;
}
Expand Down

0 comments on commit 32f91fb

Please sign in to comment.