target/arm: Split out get_zarray

Prepare for MOVA array to/from vector with multiple registers
by adding a div_len parameter, herein always 1, and a vec_mod
parameter, herein always 0.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20250704142112.1018902-24-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2025-07-04 08:19:46 -06:00 committed by Peter Maydell
parent 2c43bee917
commit 7afb9855fc

View file

@ -43,7 +43,8 @@ static bool sme2_zt0_enabled_check(DisasContext *s)
/* Resolve tile.size[rs+imm] to a host pointer. */
static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs,
int tile, int imm, bool vertical)
int tile, int imm, int div_len,
int vec_mod, bool vertical)
{
int pos, len, offset;
TCGv_i32 tmp;
@ -52,10 +53,23 @@ static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs,
/* Compute the final index, which is Rs+imm. */
tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(tmp, cpu_reg(s, rs));
/*
* Round the vector index down to a multiple of vec_mod if necessary.
* We do this before adding the offset, to handle cases like
* MOVA (tile to vector, 2 registers) where we want to call this
* several times in a loop with an increasing offset. We rely on
* the instruction encodings always forcing the initial offset in
* [rs + offset] to be a multiple of vec_mod. The pseudocode usually
* does the round-down after adding the offset rather than before,
* but MOVA is an exception.
*/
if (vec_mod > 1) {
tcg_gen_andc_i32(tmp, tmp, tcg_constant_i32(vec_mod - 1));
}
tcg_gen_addi_i32(tmp, tmp, imm);
/* Prepare a power-of-two modulo via extraction of @len bits. */
len = ctz32(streaming_vec_reg_size(s)) - esz;
len = ctz32(streaming_vec_reg_size(s) / div_len) - esz;
if (!len) {
/*
@ -111,6 +125,14 @@ static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs,
return addr;
}
/* Resolve ZArray[rs+imm] to a host pointer. */
static TCGv_ptr get_zarray(DisasContext *s, int rs, int imm,
int div_len, int vec_mod)
{
/* ZA[n] equates to ZA0H.B[n]. */
return get_tile_rowcol(s, MO_8, rs, 0, imm, div_len, vec_mod, false);
}
/*
* Resolve tile.size[0] to a host pointer.
* Used by e.g. outer product insns where we require the entire tile.
@ -177,7 +199,7 @@ static bool do_mova_tile(DisasContext *s, arg_mova_p *a, bool to_vec)
return true;
}
t_za = get_tile_rowcol(s, a->esz, a->rs, a->za, a->off, a->v);
t_za = get_tile_rowcol(s, a->esz, a->rs, a->za, a->off, 1, 0, a->v);
t_zr = vec_full_reg_ptr(s, a->zr);
t_pg = pred_full_reg_ptr(s, a->pg);
@ -259,7 +281,7 @@ static bool trans_LDST1(DisasContext *s, arg_LDST1 *a)
return true;
}
t_za = get_tile_rowcol(s, a->esz, a->rs, a->za, a->off, a->v);
t_za = get_tile_rowcol(s, a->esz, a->rs, a->za, a->off, 1, 0, a->v);
t_pg = pred_full_reg_ptr(s, a->pg);
addr = tcg_temp_new_i64();
@ -281,19 +303,14 @@ typedef void GenLdStR(DisasContext *, TCGv_ptr, int, int, int, int, MemOp);
static bool do_ldst_r(DisasContext *s, arg_ldstr *a, GenLdStR *fn)
{
int svl = streaming_vec_reg_size(s);
int imm = a->imm;
TCGv_ptr base;
if (sme_za_enabled_check(s)) {
int svl = streaming_vec_reg_size(s);
int imm = a->imm;
TCGv_ptr base = get_zarray(s, a->rv, imm, 1, 0);
if (!sme_za_enabled_check(s)) {
return true;
fn(s, base, 0, svl, a->rn, imm * svl,
s->align_mem ? MO_ALIGN_16 : MO_UNALN);
}
/* ZA[n] equates to ZA0H.B[n]. */
base = get_tile_rowcol(s, MO_8, a->rv, 0, imm, false);
fn(s, base, 0, svl, a->rn, imm * svl,
s->align_mem ? MO_ALIGN_16 : MO_UNALN);
return true;
}