In the MVE shift-and-insert insns, we special case VSLI by 0 and VSRI by <dt>, both of which mean "no shift". However we incorrectly implemented these as "don't update the destination", which works only if Qd == Qm. When Qd != Qm this kind of shift must update Qd, honouring the predicate mask.
Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> --- target/arm/mve_helper.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target/arm/mve_helper.c b/target/arm/mve_helper.c index db5d6220854..16a701933b8 100644 --- a/target/arm/mve_helper.c +++ b/target/arm/mve_helper.c @@ -1276,19 +1276,23 @@ DO_2SHIFT_S(vrshli_s, DO_VRSHLS) void *vm, uint32_t shift) \ { \ uint64_t *d = vd, *m = vm; \ - uint16_t mask; \ + uint16_t mask = mve_element_mask(env); \ uint64_t shiftmask; \ unsigned e; \ if (shift == 0 || shift == ESIZE * 8) { \ /* \ * Only VSLI can shift by 0; only VSRI can shift by <dt>. \ * The generic logic would give the right answer for 0 but \ - * fails for <dt>. \ + * fails for <dt>. In both cases, we must not shift the \ + * input but just copy it to the destination, honouring \ + * the predicate mask. \ */ \ + for (e = 0; e < 16 / 8; e++, mask >>= 8) { \ + mergemask(&d[H8(e)], m[H8(e)], mask); \ + } \ goto done; \ } \ assert(shift < ESIZE * 8); \ - mask = mve_element_mask(env); \ /* ESIZE / 2 gives the MO_* value if ESIZE is in [1,2,4] */ \ shiftmask = dup_const(ESIZE / 2, MASKFN(ESIZE * 8, shift)); \ for (e = 0; e < 16 / 8; e++, mask >>= 8) { \ -- 2.20.1