target/arm: Implement MVE interleaving loads/stores

Implement the MVE interleaving load/store functions VLD2, VLD4, VST2
and VST4.  VLD2 loads 16 bytes of data from memory and writes to 2
consecutive Qregs; VLD4 loads 16 bytes of data from memory and writes
to 4 consecutive Qregs.  The 'pattern' field in the encoding
determines the offset into memory which is accessed and also which
elements in the Qregs are written to.  (The intention is that a
sequence of four consecutive VLD4 with different pattern values
performs a complete de-interleaving load of 64 bytes into all
elements of the 4 Qregs.) VST2 and VST4 do the same, but for stores.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
master
Peter Maydell 2021-08-13 17:11:57 +01:00
parent fac80f0856
commit 075e7e97e3
4 changed files with 495 additions and 0 deletions

View File

@ -70,6 +70,54 @@ DEF_HELPER_FLAGS_4(mve_vldrd_sg_wb_ud, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(mve_vstrw_sg_wb_uw, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(mve_vstrd_sg_wb_ud, TCG_CALL_NO_WG, void, env, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(mve_vld20b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld20h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld20w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld21b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld21h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld21w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld40b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld40h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld40w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld41b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld41h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld41w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld42b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld42h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld42w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld43b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld43h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vld43w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst20b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst20h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst20w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst21b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst21h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst21w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst40b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst40h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst40w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst41b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst41h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst41w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst42b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst42h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst42w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst43b, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst43h, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vst43w, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(mve_vdup, TCG_CALL_NO_WG, void, env, ptr, i32)
DEF_HELPER_FLAGS_4(mve_vidupb, TCG_CALL_NO_WG, i32, env, ptr, i32, i32)

View File

@ -44,6 +44,7 @@
&vabav qn qm rda size
&vldst_sg qd qm rn size msize os
&vldst_sg_imm qd qm a w imm
&vldst_il qd rn size pat w
# scatter-gather memory size is in bits 6:4
%sg_msize 6:1 4:1
@ -59,6 +60,10 @@
@vldst_sg_imm .... .... a:1 . w:1 . .... .... .... . imm:7 &vldst_sg_imm \
qd=%qd qm=%qn
# Deinterleaving load/interleaving store
@vldst_il .... .... .. w:1 . rn:4 .... ... size:2 pat:2 ..... &vldst_il \
qd=%qd
@1op .... .... .... size:2 .. .... .... .... .... &1op qd=%qd qm=%qm
@1op_nosz .... .... .... .... .... .... .... .... &1op qd=%qd qm=%qm size=0
@2op .... .... .. size:2 .... .... .... .... .... &2op qd=%qd qm=%qm qn=%qn
@ -158,6 +163,12 @@ VLDRD_sg_imm 111 1 1101 ... 1 ... 0 ... 1 1111 .... .... @vldst_sg_imm
VSTRW_sg_imm 111 1 1101 ... 0 ... 0 ... 1 1110 .... .... @vldst_sg_imm
VSTRD_sg_imm 111 1 1101 ... 0 ... 0 ... 1 1111 .... .... @vldst_sg_imm
# deinterleaving loads/interleaving stores
VLD2 1111 1100 1 .. 1 .... ... 1 111 .. .. 00000 @vldst_il
VLD4 1111 1100 1 .. 1 .... ... 1 111 .. .. 00001 @vldst_il
VST2 1111 1100 1 .. 0 .... ... 1 111 .. .. 00000 @vldst_il
VST4 1111 1100 1 .. 0 .... ... 1 111 .. .. 00001 @vldst_il
# 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

View File

@ -362,6 +362,348 @@ DO_VLDR64_SG(vldrd_sg_wb_ud, ADDR_ADD, true)
DO_VSTR_SG(vstrw_sg_wb_uw, stl, 4, uint32_t, ADDR_ADD, true)
DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true)
/*
* Deinterleaving loads/interleaving stores.
*
* For these helpers we are passed the index of the first Qreg
* (VLD2/VST2 will also access Qn+1, VLD4/VST4 access Qn .. Qn+3)
* and the value of the base address register Rn.
* The helpers are specialized for pattern and element size, so
* for instance vld42h is VLD4 with pattern 2, element size MO_16.
*
* These insns are beatwise but not predicated, so we must honour ECI,
* but need not look at mve_element_mask().
*
* The pseudocode implements these insns with multiple memory accesses
* of the element size, but rules R_VVVG and R_FXDM permit us to make
* one 32-bit memory access per beat.
*/
#define DO_VLD4B(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat, e; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
for (e = 0; e < 4; e++, data >>= 8) { \
uint8_t *qd = (uint8_t *)aa32_vfp_qreg(env, qnidx + e); \
qd[H1(off[beat])] = data; \
} \
} \
}
#define DO_VLD4H(OP, O1, O2) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O1, O2, O2 }; \
uint32_t addr, data; \
int y; /* y counts 0 2 0 2 */ \
uint16_t *qd; \
for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 8 + (beat & 1) * 4; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + y); \
qd[H2(off[beat])] = data; \
data >>= 16; \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + y + 1); \
qd[H2(off[beat])] = data; \
} \
}
#define DO_VLD4W(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint32_t *qd; \
int y; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
y = (beat + (O1 & 2)) & 3; \
qd = (uint32_t *)aa32_vfp_qreg(env, qnidx + y); \
qd[H4(off[beat] >> 2)] = data; \
} \
}
DO_VLD4B(vld40b, 0, 1, 10, 11)
DO_VLD4B(vld41b, 2, 3, 12, 13)
DO_VLD4B(vld42b, 4, 5, 14, 15)
DO_VLD4B(vld43b, 6, 7, 8, 9)
DO_VLD4H(vld40h, 0, 5)
DO_VLD4H(vld41h, 1, 6)
DO_VLD4H(vld42h, 2, 7)
DO_VLD4H(vld43h, 3, 4)
DO_VLD4W(vld40w, 0, 1, 10, 11)
DO_VLD4W(vld41w, 2, 3, 12, 13)
DO_VLD4W(vld42w, 4, 5, 14, 15)
DO_VLD4W(vld43w, 6, 7, 8, 9)
#define DO_VLD2B(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat, e; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint8_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 2; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
for (e = 0; e < 4; e++, data >>= 8) { \
qd = (uint8_t *)aa32_vfp_qreg(env, qnidx + (e & 1)); \
qd[H1(off[beat] + (e >> 1))] = data; \
} \
} \
}
#define DO_VLD2H(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
int e; \
uint16_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
for (e = 0; e < 2; e++, data >>= 16) { \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + e); \
qd[H2(off[beat])] = data; \
} \
} \
}
#define DO_VLD2W(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint32_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat]; \
data = cpu_ldl_le_data_ra(env, addr, GETPC()); \
qd = (uint32_t *)aa32_vfp_qreg(env, qnidx + (beat & 1)); \
qd[H4(off[beat] >> 3)] = data; \
} \
}
DO_VLD2B(vld20b, 0, 2, 12, 14)
DO_VLD2B(vld21b, 4, 6, 8, 10)
DO_VLD2H(vld20h, 0, 1, 6, 7)
DO_VLD2H(vld21h, 2, 3, 4, 5)
DO_VLD2W(vld20w, 0, 4, 24, 28)
DO_VLD2W(vld21w, 8, 12, 16, 20)
#define DO_VST4B(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat, e; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
data = 0; \
for (e = 3; e >= 0; e--) { \
uint8_t *qd = (uint8_t *)aa32_vfp_qreg(env, qnidx + e); \
data = (data << 8) | qd[H1(off[beat])]; \
} \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
#define DO_VST4H(OP, O1, O2) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O1, O2, O2 }; \
uint32_t addr, data; \
int y; /* y counts 0 2 0 2 */ \
uint16_t *qd; \
for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 8 + (beat & 1) * 4; \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + y); \
data = qd[H2(off[beat])]; \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + y + 1); \
data |= qd[H2(off[beat])] << 16; \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
#define DO_VST4W(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint32_t *qd; \
int y; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
y = (beat + (O1 & 2)) & 3; \
qd = (uint32_t *)aa32_vfp_qreg(env, qnidx + y); \
data = qd[H4(off[beat] >> 2)]; \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
DO_VST4B(vst40b, 0, 1, 10, 11)
DO_VST4B(vst41b, 2, 3, 12, 13)
DO_VST4B(vst42b, 4, 5, 14, 15)
DO_VST4B(vst43b, 6, 7, 8, 9)
DO_VST4H(vst40h, 0, 5)
DO_VST4H(vst41h, 1, 6)
DO_VST4H(vst42h, 2, 7)
DO_VST4H(vst43h, 3, 4)
DO_VST4W(vst40w, 0, 1, 10, 11)
DO_VST4W(vst41w, 2, 3, 12, 13)
DO_VST4W(vst42w, 4, 5, 14, 15)
DO_VST4W(vst43w, 6, 7, 8, 9)
#define DO_VST2B(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat, e; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint8_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 2; \
data = 0; \
for (e = 3; e >= 0; e--) { \
qd = (uint8_t *)aa32_vfp_qreg(env, qnidx + (e & 1)); \
data = (data << 8) | qd[H1(off[beat] + (e >> 1))]; \
} \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
#define DO_VST2H(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
int e; \
uint16_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat] * 4; \
data = 0; \
for (e = 1; e >= 0; e--) { \
qd = (uint16_t *)aa32_vfp_qreg(env, qnidx + e); \
data = (data << 16) | qd[H2(off[beat])]; \
} \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
#define DO_VST2W(OP, O1, O2, O3, O4) \
void HELPER(mve_##OP)(CPUARMState *env, uint32_t qnidx, \
uint32_t base) \
{ \
int beat; \
uint16_t mask = mve_eci_mask(env); \
static const uint8_t off[4] = { O1, O2, O3, O4 }; \
uint32_t addr, data; \
uint32_t *qd; \
for (beat = 0; beat < 4; beat++, mask >>= 4) { \
if ((mask & 1) == 0) { \
/* ECI says skip this beat */ \
continue; \
} \
addr = base + off[beat]; \
qd = (uint32_t *)aa32_vfp_qreg(env, qnidx + (beat & 1)); \
data = qd[H4(off[beat] >> 3)]; \
cpu_stl_le_data_ra(env, addr, data, GETPC()); \
} \
}
DO_VST2B(vst20b, 0, 2, 12, 14)
DO_VST2B(vst21b, 4, 6, 8, 10)
DO_VST2H(vst20h, 0, 1, 6, 7)
DO_VST2H(vst21h, 2, 3, 4, 5)
DO_VST2W(vst20w, 0, 4, 24, 28)
DO_VST2W(vst21w, 8, 12, 16, 20)
/*
* The mergemask(D, R, M) macro performs the operation "*D = R" but
* storing only the bytes which correspond to 1 bits in M,

View File

@ -35,6 +35,7 @@ static inline int vidup_imm(DisasContext *s, int x)
typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
typedef void MVEGenLdStSGFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
typedef void MVEGenLdStIlFn(TCGv_ptr, TCGv_i32, TCGv_i32);
typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
@ -378,6 +379,99 @@ static bool trans_VSTRD_sg_imm(DisasContext *s, arg_vldst_sg_imm *a)
return do_ldst_sg_imm(s, a, fns[a->w], MO_64);
}
static bool do_vldst_il(DisasContext *s, arg_vldst_il *a, MVEGenLdStIlFn *fn,
int addrinc)
{
TCGv_i32 rn;
if (!dc_isar_feature(aa32_mve, s) ||
!mve_check_qreg_bank(s, a->qd) ||
!fn || (a->rn == 13 && a->w) || a->rn == 15) {
/* Variously UNPREDICTABLE or UNDEF or related-encoding */
return false;
}
if (!mve_eci_check(s) || !vfp_access_check(s)) {
return true;
}
rn = load_reg(s, a->rn);
/*
* We pass the index of Qd, not a pointer, because the helper must
* access multiple Q registers starting at Qd and working up.
*/
fn(cpu_env, tcg_constant_i32(a->qd), rn);
if (a->w) {
tcg_gen_addi_i32(rn, rn, addrinc);
store_reg(s, a->rn, rn);
} else {
tcg_temp_free_i32(rn);
}
mve_update_and_store_eci(s);
return true;
}
/* This macro is just to make the arrays more compact in these functions */
#define F(N) gen_helper_mve_##N
static bool trans_VLD2(DisasContext *s, arg_vldst_il *a)
{
static MVEGenLdStIlFn * const fns[4][4] = {
{ F(vld20b), F(vld20h), F(vld20w), NULL, },
{ F(vld21b), F(vld21h), F(vld21w), NULL, },
{ NULL, NULL, NULL, NULL },
{ NULL, NULL, NULL, NULL },
};
if (a->qd > 6) {
return false;
}
return do_vldst_il(s, a, fns[a->pat][a->size], 32);
}
static bool trans_VLD4(DisasContext *s, arg_vldst_il *a)
{
static MVEGenLdStIlFn * const fns[4][4] = {
{ F(vld40b), F(vld40h), F(vld40w), NULL, },
{ F(vld41b), F(vld41h), F(vld41w), NULL, },
{ F(vld42b), F(vld42h), F(vld42w), NULL, },
{ F(vld43b), F(vld43h), F(vld43w), NULL, },
};
if (a->qd > 4) {
return false;
}
return do_vldst_il(s, a, fns[a->pat][a->size], 64);
}
static bool trans_VST2(DisasContext *s, arg_vldst_il *a)
{
static MVEGenLdStIlFn * const fns[4][4] = {
{ F(vst20b), F(vst20h), F(vst20w), NULL, },
{ F(vst21b), F(vst21h), F(vst21w), NULL, },
{ NULL, NULL, NULL, NULL },
{ NULL, NULL, NULL, NULL },
};
if (a->qd > 6) {
return false;
}
return do_vldst_il(s, a, fns[a->pat][a->size], 32);
}
static bool trans_VST4(DisasContext *s, arg_vldst_il *a)
{
static MVEGenLdStIlFn * const fns[4][4] = {
{ F(vst40b), F(vst40h), F(vst40w), NULL, },
{ F(vst41b), F(vst41h), F(vst41w), NULL, },
{ F(vst42b), F(vst42h), F(vst42w), NULL, },
{ F(vst43b), F(vst43h), F(vst43w), NULL, },
};
if (a->qd > 4) {
return false;
}
return do_vldst_il(s, a, fns[a->pat][a->size], 64);
}
#undef F
static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
{
TCGv_ptr qd;