mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-22 23:01:02 +00:00
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. Backports commit 32f91fb71f4c32113ec8c2af5f74f14abe6c7162 from qemu
This commit is contained in:
parent
3d5f040608
commit
c1251a19e1
|
@ -1655,6 +1655,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(DisasContext *s, int reg, int pass)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
@ -3552,17 +3571,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(s, tmp, 0);
|
||||
} else if (size == 1) {
|
||||
gen_neon_dup_low16(s, tmp);
|
||||
}
|
||||
for (n = 0; n <= pass * 2; n++) {
|
||||
tmp2 = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_mov_i32(tcg_ctx, tmp2, tmp);
|
||||
neon_store_reg(s, rn, n, tmp2);
|
||||
}
|
||||
neon_store_reg(s, rn, n, tmp);
|
||||
int vec_size = pass ? 16 : 8;
|
||||
tcg_gen_gvec_dup_i32(tcg_ctx, size, neon_reg_offset(rn, 0),
|
||||
vec_size, vec_size, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
} else {
|
||||
/* VMOV */
|
||||
switch (size) {
|
||||
|
@ -7921,28 +7933,25 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tcg_ctx, 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(s, rm, 1);
|
||||
} else {
|
||||
tmp = neon_load_reg(s, rm, 0);
|
||||
}
|
||||
if (insn & (1 << 16)) {
|
||||
gen_neon_dup_u8(s, 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(s, tmp);
|
||||
else
|
||||
gen_neon_dup_low16(s, 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_ctx);
|
||||
tcg_gen_mov_i32(tcg_ctx, tmp2, tmp);
|
||||
neon_store_reg(s, rd, pass, tmp2);
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
tcg_gen_gvec_dup_mem(tcg_ctx, size, neon_reg_offset(rd, 0),
|
||||
neon_element_offset(rm, element, size),
|
||||
q ? 16 : 8, q ? 16 : 8);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue