target/arm: Implement MVE incrementing/decrementing dup insns

Implement the MVE incrementing/decrementing dup insns VIDUP, VDDUP,
VIWDUP and VDWDUP.  These fill the elements of a vector with
successively incrementing values, starting at the offset specified in
a general purpose register.  The final value of the offset is written
back to this register.  The wrapping variants take a second general
purpose register which specifies the point where the count should
wrap back to 0.

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:50 +01:00
parent c1bd78cb06
commit 395b92d50e
4 changed files with 220 additions and 0 deletions

View file

@ -1695,3 +1695,66 @@ uint32_t HELPER(mve_sqrshr)(CPUARMState *env, uint32_t n, uint32_t shift)
{
return do_sqrshl_bhs(n, -(int8_t)shift, 32, true, &env->QF);
}
#define DO_VIDUP(OP, ESIZE, TYPE, FN) \
uint32_t HELPER(mve_##OP)(CPUARMState *env, void *vd, \
uint32_t offset, uint32_t imm) \
{ \
TYPE *d = vd; \
uint16_t mask = mve_element_mask(env); \
unsigned e; \
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
mergemask(&d[H##ESIZE(e)], offset, mask); \
offset = FN(offset, imm); \
} \
mve_advance_vpt(env); \
return offset; \
}
#define DO_VIWDUP(OP, ESIZE, TYPE, FN) \
uint32_t HELPER(mve_##OP)(CPUARMState *env, void *vd, \
uint32_t offset, uint32_t wrap, \
uint32_t imm) \
{ \
TYPE *d = vd; \
uint16_t mask = mve_element_mask(env); \
unsigned e; \
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
mergemask(&d[H##ESIZE(e)], offset, mask); \
offset = FN(offset, wrap, imm); \
} \
mve_advance_vpt(env); \
return offset; \
}
#define DO_VIDUP_ALL(OP, FN) \
DO_VIDUP(OP##b, 1, int8_t, FN) \
DO_VIDUP(OP##h, 2, int16_t, FN) \
DO_VIDUP(OP##w, 4, int32_t, FN)
#define DO_VIWDUP_ALL(OP, FN) \
DO_VIWDUP(OP##b, 1, int8_t, FN) \
DO_VIWDUP(OP##h, 2, int16_t, FN) \
DO_VIWDUP(OP##w, 4, int32_t, FN)
static uint32_t do_add_wrap(uint32_t offset, uint32_t wrap, uint32_t imm)
{
offset += imm;
if (offset == wrap) {
offset = 0;
}
return offset;
}
static uint32_t do_sub_wrap(uint32_t offset, uint32_t wrap, uint32_t imm)
{
if (offset == 0) {
offset = wrap;
}
offset -= imm;
return offset;
}
DO_VIDUP_ALL(vidup, DO_ADD)
DO_VIWDUP_ALL(viwdup, do_add_wrap)
DO_VIWDUP_ALL(vdwdup, do_sub_wrap)