target/arm: Implement MVE VMOV to/from 2 general-purpose registers

Implement the MVE VMOV forms that move data between 2 general-purpose
registers and 2 32-bit lanes in a vector register.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Peter Maydell 2021-08-13 17:11:55 +01:00
parent d5c571ea6d
commit 1241f148d5
4 changed files with 91 additions and 1 deletions

View File

@ -136,6 +136,10 @@ VLDR_VSTR 1110110 1 a:1 . w:1 . .... ... 111101 ....... @vldr_vstr \
VLDR_VSTR 1110110 1 a:1 . w:1 . .... ... 111110 ....... @vldr_vstr \ VLDR_VSTR 1110110 1 a:1 . w:1 . .... ... 111110 ....... @vldr_vstr \
size=2 p=1 size=2 p=1
# Moves between 2 32-bit vector lanes and 2 general purpose registers
VMOV_to_2gp 1110 1100 0 . 00 rt2:4 ... 0 1111 000 idx:1 rt:4 qd=%qd
VMOV_from_2gp 1110 1100 0 . 01 rt2:4 ... 0 1111 000 idx:1 rt:4 qd=%qd
# Vector 2-op # Vector 2-op
VAND 1110 1111 0 . 00 ... 0 ... 0 0001 . 1 . 1 ... 0 @2op_nosz VAND 1110 1111 0 . 00 ... 0 ... 0 0001 . 1 . 1 ... 0 @2op_nosz
VBIC 1110 1111 0 . 01 ... 0 ... 0 0001 . 1 . 1 ... 0 @2op_nosz VBIC 1110 1111 0 . 01 ... 0 ... 0 0001 . 1 . 1 ... 0 @2op_nosz

View File

@ -49,6 +49,7 @@ void gen_rev16(TCGv_i32 dest, TCGv_i32 var);
void clear_eci_state(DisasContext *s); void clear_eci_state(DisasContext *s);
bool mve_eci_check(DisasContext *s); bool mve_eci_check(DisasContext *s);
void mve_update_and_store_eci(DisasContext *s); void mve_update_and_store_eci(DisasContext *s);
bool mve_skip_vmov(DisasContext *s, int vn, int index, int size);
static inline TCGv_i32 load_cpu_offset(int offset) static inline TCGv_i32 load_cpu_offset(int offset)
{ {

View File

@ -1507,3 +1507,88 @@ static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
DO_VABAV(VABAV_S, vabavs) DO_VABAV(VABAV_S, vabavs)
DO_VABAV(VABAV_U, vabavu) DO_VABAV(VABAV_U, vabavu)
static bool trans_VMOV_to_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
{
/*
* VMOV two 32-bit vector lanes to two general-purpose registers.
* This insn is not predicated but it is subject to beat-wise
* execution if it is not in an IT block. For us this means
* only that if PSR.ECI says we should not be executing the beat
* corresponding to the lane of the vector register being accessed
* then we should skip perfoming the move, and that we need to do
* the usual check for bad ECI state and advance of ECI state.
* (If PSR.ECI is non-zero then we cannot be in an IT block.)
*/
TCGv_i32 tmp;
int vd;
if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15 ||
a->rt == a->rt2) {
/* Rt/Rt2 cases are UNPREDICTABLE */
return false;
}
if (!mve_eci_check(s) || !vfp_access_check(s)) {
return true;
}
/* Convert Qreg index to Dreg for read_neon_element32() etc */
vd = a->qd * 2;
if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
tmp = tcg_temp_new_i32();
read_neon_element32(tmp, vd, a->idx, MO_32);
store_reg(s, a->rt, tmp);
}
if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
tmp = tcg_temp_new_i32();
read_neon_element32(tmp, vd + 1, a->idx, MO_32);
store_reg(s, a->rt2, tmp);
}
mve_update_and_store_eci(s);
return true;
}
static bool trans_VMOV_from_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
{
/*
* VMOV two general-purpose registers to two 32-bit vector lanes.
* This insn is not predicated but it is subject to beat-wise
* execution if it is not in an IT block. For us this means
* only that if PSR.ECI says we should not be executing the beat
* corresponding to the lane of the vector register being accessed
* then we should skip perfoming the move, and that we need to do
* the usual check for bad ECI state and advance of ECI state.
* (If PSR.ECI is non-zero then we cannot be in an IT block.)
*/
TCGv_i32 tmp;
int vd;
if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15) {
/* Rt/Rt2 cases are UNPREDICTABLE */
return false;
}
if (!mve_eci_check(s) || !vfp_access_check(s)) {
return true;
}
/* Convert Qreg idx to Dreg for read_neon_element32() etc */
vd = a->qd * 2;
if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
tmp = load_reg(s, a->rt);
write_neon_element32(tmp, vd, a->idx, MO_32);
tcg_temp_free_i32(tmp);
}
if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
tmp = load_reg(s, a->rt2);
write_neon_element32(tmp, vd + 1, a->idx, MO_32);
tcg_temp_free_i32(tmp);
}
mve_update_and_store_eci(s);
return true;
}

View File

@ -581,7 +581,7 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
return true; return true;
} }
static bool mve_skip_vmov(DisasContext *s, int vn, int index, int size) bool mve_skip_vmov(DisasContext *s, int vn, int index, int size)
{ {
/* /*
* In a CPU with MVE, the VMOV (vector lane to general-purpose register) * In a CPU with MVE, the VMOV (vector lane to general-purpose register)