target/arm: Convert load/store tags insns to decodetree

Convert the instructions in the load/store memory tags instruction
group to decodetree.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20230602155223.2040685-21-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2023-06-19 11:20:24 +01:00
parent 3d50721326
commit 946ccfd590
2 changed files with 199 additions and 186 deletions

View File

@ -528,3 +528,28 @@ LD_single 0 . 001101 . 1 . ..... 10 . 001 ..... ..... @ldst_single_d
# Replicating load case
LD_single_repl 0 q:1 001101 p:1 1 . rm:5 11 . 0 scale:2 rn:5 rt:5 selem=%ldst_single_selem
%tag_offset 12:s9 !function=scale_by_log2_tag_granule
&ldst_tag rn rt imm p w
@ldst_tag ........ .. . ......... .. rn:5 rt:5 &ldst_tag imm=%tag_offset
@ldst_tag_mult ........ .. . 000000000 .. rn:5 rt:5 &ldst_tag imm=0
STZGM 11011001 00 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
STG 11011001 00 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
STG 11011001 00 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
STG 11011001 00 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
LDG 11011001 01 1 ......... 00 ..... ..... @ldst_tag p=0 w=0
STZG 11011001 01 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
STZG 11011001 01 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
STZG 11011001 01 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
STGM 11011001 10 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
ST2G 11011001 10 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
ST2G 11011001 10 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
ST2G 11011001 10 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
LDGM 11011001 11 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
STZ2G 11011001 11 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
STZ2G 11011001 11 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
STZ2G 11011001 11 1 ......... 11 ..... ..... @ldst_tag p=0 w=1

View File

@ -62,6 +62,12 @@ static int uimm_scaled(DisasContext *s, int x)
return imm << scale;
}
/* For load/store memory tags: scale offset by LOG2_TAG_GRANULE */
static int scale_by_log2_tag_granule(DisasContext *s, int x)
{
return x << LOG2_TAG_GRANULE;
}
/*
* Include the generated decoders.
*/
@ -3709,185 +3715,184 @@ static bool trans_LD_single_repl(DisasContext *s, arg_LD_single_repl *a)
return true;
}
/*
* Load/Store memory tags
*
* 31 30 29 24 22 21 12 10 5 0
* +-----+-------------+-----+---+------+-----+------+------+
* | 1 1 | 0 1 1 0 0 1 | op1 | 1 | imm9 | op2 | Rn | Rt |
* +-----+-------------+-----+---+------+-----+------+------+
*/
static void disas_ldst_tag(DisasContext *s, uint32_t insn)
static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a)
{
int rt = extract32(insn, 0, 5);
int rn = extract32(insn, 5, 5);
uint64_t offset = sextract64(insn, 12, 9) << LOG2_TAG_GRANULE;
int op2 = extract32(insn, 10, 2);
int op1 = extract32(insn, 22, 2);
bool is_load = false, is_pair = false, is_zero = false, is_mult = false;
int index = 0;
TCGv_i64 addr, clean_addr, tcg_rt;
int size = 4 << s->dcz_blocksize;
/* We checked insn bits [29:24,21] in the caller. */
if (extract32(insn, 30, 2) != 3) {
goto do_unallocated;
if (!dc_isar_feature(aa64_mte, s)) {
return false;
}
if (s->current_el == 0) {
return false;
}
/*
* @index is a tri-state variable which has 3 states:
* < 0 : post-index, writeback
* = 0 : signed offset
* > 0 : pre-index, writeback
*/
switch (op1) {
case 0:
if (op2 != 0) {
/* STG */
index = op2 - 2;
} else {
/* STZGM */
if (s->current_el == 0 || offset != 0) {
goto do_unallocated;
}
is_mult = is_zero = true;
}
break;
case 1:
if (op2 != 0) {
/* STZG */
is_zero = true;
index = op2 - 2;
} else {
/* LDG */
is_load = true;
}
break;
case 2:
if (op2 != 0) {
/* ST2G */
is_pair = true;
index = op2 - 2;
} else {
/* STGM */
if (s->current_el == 0 || offset != 0) {
goto do_unallocated;
}
is_mult = true;
}
break;
case 3:
if (op2 != 0) {
/* STZ2G */
is_pair = is_zero = true;
index = op2 - 2;
} else {
/* LDGM */
if (s->current_el == 0 || offset != 0) {
goto do_unallocated;
}
is_mult = is_load = true;
}
break;
default:
do_unallocated:
unallocated_encoding(s);
return;
}
if (is_mult
? !dc_isar_feature(aa64_mte, s)
: !dc_isar_feature(aa64_mte_insn_reg, s)) {
goto do_unallocated;
}
if (rn == 31) {
if (a->rn == 31) {
gen_check_sp_alignment(s);
}
addr = read_cpu_reg_sp(s, rn, true);
if (index >= 0) {
addr = read_cpu_reg_sp(s, a->rn, true);
tcg_gen_addi_i64(addr, addr, a->imm);
tcg_rt = cpu_reg(s, a->rt);
if (s->ata) {
gen_helper_stzgm_tags(cpu_env, addr, tcg_rt);
}
/*
* The non-tags portion of STZGM is mostly like DC_ZVA,
* except the alignment happens before the access.
*/
clean_addr = clean_data_tbi(s, addr);
tcg_gen_andi_i64(clean_addr, clean_addr, -size);
gen_helper_dc_zva(cpu_env, clean_addr);
return true;
}
static bool trans_STGM(DisasContext *s, arg_ldst_tag *a)
{
TCGv_i64 addr, clean_addr, tcg_rt;
if (!dc_isar_feature(aa64_mte, s)) {
return false;
}
if (s->current_el == 0) {
return false;
}
if (a->rn == 31) {
gen_check_sp_alignment(s);
}
addr = read_cpu_reg_sp(s, a->rn, true);
tcg_gen_addi_i64(addr, addr, a->imm);
tcg_rt = cpu_reg(s, a->rt);
if (s->ata) {
gen_helper_stgm(cpu_env, addr, tcg_rt);
} else {
MMUAccessType acc = MMU_DATA_STORE;
int size = 4 << GMID_EL1_BS;
clean_addr = clean_data_tbi(s, addr);
tcg_gen_andi_i64(clean_addr, clean_addr, -size);
gen_probe_access(s, clean_addr, acc, size);
}
return true;
}
static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a)
{
TCGv_i64 addr, clean_addr, tcg_rt;
if (!dc_isar_feature(aa64_mte, s)) {
return false;
}
if (s->current_el == 0) {
return false;
}
if (a->rn == 31) {
gen_check_sp_alignment(s);
}
addr = read_cpu_reg_sp(s, a->rn, true);
tcg_gen_addi_i64(addr, addr, a->imm);
tcg_rt = cpu_reg(s, a->rt);
if (s->ata) {
gen_helper_ldgm(tcg_rt, cpu_env, addr);
} else {
MMUAccessType acc = MMU_DATA_LOAD;
int size = 4 << GMID_EL1_BS;
clean_addr = clean_data_tbi(s, addr);
tcg_gen_andi_i64(clean_addr, clean_addr, -size);
gen_probe_access(s, clean_addr, acc, size);
/* The result tags are zeros. */
tcg_gen_movi_i64(tcg_rt, 0);
}
return true;
}
static bool trans_LDG(DisasContext *s, arg_ldst_tag *a)
{
TCGv_i64 addr, clean_addr, tcg_rt;
if (!dc_isar_feature(aa64_mte_insn_reg, s)) {
return false;
}
if (a->rn == 31) {
gen_check_sp_alignment(s);
}
addr = read_cpu_reg_sp(s, a->rn, true);
if (!a->p) {
/* pre-index or signed offset */
tcg_gen_addi_i64(addr, addr, offset);
tcg_gen_addi_i64(addr, addr, a->imm);
}
if (is_mult) {
tcg_rt = cpu_reg(s, rt);
tcg_gen_andi_i64(addr, addr, -TAG_GRANULE);
tcg_rt = cpu_reg(s, a->rt);
if (s->ata) {
gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
} else {
/*
* Tag access disabled: we must check for aborts on the load
* load from [rn+offset], and then insert a 0 tag into rt.
*/
clean_addr = clean_data_tbi(s, addr);
gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
}
if (is_zero) {
int size = 4 << s->dcz_blocksize;
if (s->ata) {
gen_helper_stzgm_tags(cpu_env, addr, tcg_rt);
}
/*
* The non-tags portion of STZGM is mostly like DC_ZVA,
* except the alignment happens before the access.
*/
clean_addr = clean_data_tbi(s, addr);
tcg_gen_andi_i64(clean_addr, clean_addr, -size);
gen_helper_dc_zva(cpu_env, clean_addr);
} else if (s->ata) {
if (is_load) {
gen_helper_ldgm(tcg_rt, cpu_env, addr);
} else {
gen_helper_stgm(cpu_env, addr, tcg_rt);
}
} else {
MMUAccessType acc = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE;
int size = 4 << GMID_EL1_BS;
clean_addr = clean_data_tbi(s, addr);
tcg_gen_andi_i64(clean_addr, clean_addr, -size);
gen_probe_access(s, clean_addr, acc, size);
if (is_load) {
/* The result tags are zeros. */
tcg_gen_movi_i64(tcg_rt, 0);
}
if (a->w) {
/* pre-index or post-index */
if (a->p) {
/* post-index */
tcg_gen_addi_i64(addr, addr, a->imm);
}
return;
tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
}
return true;
}
static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair)
{
TCGv_i64 addr, tcg_rt;
if (a->rn == 31) {
gen_check_sp_alignment(s);
}
if (is_load) {
tcg_gen_andi_i64(addr, addr, -TAG_GRANULE);
tcg_rt = cpu_reg(s, rt);
if (s->ata) {
gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
addr = read_cpu_reg_sp(s, a->rn, true);
if (!a->p) {
/* pre-index or signed offset */
tcg_gen_addi_i64(addr, addr, a->imm);
}
tcg_rt = cpu_reg_sp(s, a->rt);
if (!s->ata) {
/*
* For STG and ST2G, we need to check alignment and probe memory.
* TODO: For STZG and STZ2G, we could rely on the stores below,
* at least for system mode; user-only won't enforce alignment.
*/
if (is_pair) {
gen_helper_st2g_stub(cpu_env, addr);
} else {
/*
* Tag access disabled: we must check for aborts on the load
* load from [rn+offset], and then insert a 0 tag into rt.
*/
clean_addr = clean_data_tbi(s, addr);
gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
gen_helper_stg_stub(cpu_env, addr);
}
} else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
if (is_pair) {
gen_helper_st2g_parallel(cpu_env, addr, tcg_rt);
} else {
gen_helper_stg_parallel(cpu_env, addr, tcg_rt);
}
} else {
tcg_rt = cpu_reg_sp(s, rt);
if (!s->ata) {
/*
* For STG and ST2G, we need to check alignment and probe memory.
* TODO: For STZG and STZ2G, we could rely on the stores below,
* at least for system mode; user-only won't enforce alignment.
*/
if (is_pair) {
gen_helper_st2g_stub(cpu_env, addr);
} else {
gen_helper_stg_stub(cpu_env, addr);
}
} else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
if (is_pair) {
gen_helper_st2g_parallel(cpu_env, addr, tcg_rt);
} else {
gen_helper_stg_parallel(cpu_env, addr, tcg_rt);
}
if (is_pair) {
gen_helper_st2g(cpu_env, addr, tcg_rt);
} else {
if (is_pair) {
gen_helper_st2g(cpu_env, addr, tcg_rt);
} else {
gen_helper_stg(cpu_env, addr, tcg_rt);
}
gen_helper_stg(cpu_env, addr, tcg_rt);
}
}
@ -3908,32 +3913,21 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
}
}
if (index != 0) {
if (a->w) {
/* pre-index or post-index */
if (index < 0) {
if (a->p) {
/* post-index */
tcg_gen_addi_i64(addr, addr, offset);
tcg_gen_addi_i64(addr, addr, a->imm);
}
tcg_gen_mov_i64(cpu_reg_sp(s, rn), addr);
tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
}
return true;
}
/* Loads and stores */
static void disas_ldst(DisasContext *s, uint32_t insn)
{
switch (extract32(insn, 24, 6)) {
case 0x19:
if (extract32(insn, 21, 1) != 0) {
disas_ldst_tag(s, insn);
} else {
unallocated_encoding(s);
}
break;
default:
unallocated_encoding(s);
break;
}
}
TRANS_FEAT(STG, aa64_mte_insn_reg, do_STG, a, false, false)
TRANS_FEAT(STZG, aa64_mte_insn_reg, do_STG, a, true, false)
TRANS_FEAT(ST2G, aa64_mte_insn_reg, do_STG, a, false, true)
TRANS_FEAT(STZ2G, aa64_mte_insn_reg, do_STG, a, true, true)
typedef void ArithTwoOp(TCGv_i64, TCGv_i64, TCGv_i64);
@ -13829,12 +13823,6 @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
static void disas_a64_legacy(DisasContext *s, uint32_t insn)
{
switch (extract32(insn, 25, 4)) {
case 0x4:
case 0x6:
case 0xc:
case 0xe: /* Loads and stores */
disas_ldst(s, insn);
break;
case 0x5:
case 0xd: /* Data processing - register */
disas_data_proc_reg(s, insn);