@samitouri / QOSamiQemu / commits / 12670c82c3

target/arm: mte_check unemitted on STORE_ONLY load

This feature disables generation of the mte check helper on loads when STORE_ONLY tag checking mode is enabled. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-3-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Gabriel Brookman committed May 29, 2026 at 12:52 UTC 12670c82c344b0ab1f989222456222e2dcfff287
4 files changed +22 -2
target/arm/cpu.h
+2
@@ -2534,6 +2534,8 @@ FIELD(TBFLAG_A64, GCS_EN, 41, 1)
2534 FIELD(TBFLAG_A64, GCS_RVCEN, 42, 1)
2535 FIELD(TBFLAG_A64, GCSSTR_EL, 43, 2)
2536 FIELD(TBFLAG_A64, FPMR_EL, 45, 2)
2537 +FIELD(TBFLAG_A64, MTE_STORE_ONLY, 47, 1)
2538 +FIELD(TBFLAG_A64, MTE0_STORE_ONLY, 48, 1)
2539
2540 /*
2541 * Helpers for using the above. Note that only the A64 accessors use
target/arm/tcg/hflags.c
+12
@@ -461,6 +461,15 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
461 */
462 DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1);
463 }
464 + /*
465 + * Repeat for MTE_STORE_ONLY
466 + */
467 + if ((el == 0 ? SCTLR_TCSO0 : SCTLR_TCSO) & sctlr) {
468 + DP_TBFLAG_A64(flags, MTE_STORE_ONLY, 1);
469 + if (!EX_TBFLAG_A64(flags, UNPRIV)) {
470 + DP_TBFLAG_A64(flags, MTE0_STORE_ONLY, 1);
471 + }
472 + }
473 }
474 }
475 /* And again for unprivileged accesses, if required. */
@@ -470,6 +479,9 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
479 && (sctlr & SCTLR_TCF0)
480 && allocation_tag_access_enabled(env, 0, sctlr)) {
481 DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1);
482 + if (SCTLR_TCSO0 & sctlr) {
483 + DP_TBFLAG_A64(flags, MTE0_STORE_ONLY, 1);
484 + }
485 }
486 /*
487 * For unpriv tag-setting accesses we also need ATA0. Again, in
target/arm/tcg/translate-a64.c
+6 -2
@@ -302,7 +302,8 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
302 MemOp memop, bool is_unpriv,
303 int core_idx)
304 {
305 - if (tag_checked && s->mte_active[is_unpriv]) {
305 + if (tag_checked && s->mte_active[is_unpriv] &&
306 + (is_write || !s->mte_store_only[is_unpriv])) {
307 TCGv_i64 ret;
308 int desc = 0;
309
@@ -334,7 +335,8 @@ TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
335 TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
336 bool tag_checked, int total_size, MemOp single_mop)
337 {
337 - if (tag_checked && s->mte_active[0]) {
338 + if (tag_checked && s->mte_active[0] &&
339 + (is_write || !s->mte_store_only[0])) {
340 TCGv_i64 ret;
341 int desc = 0;
342
@@ -10805,6 +10807,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
10807 dc->ata[1] = EX_TBFLAG_A64(tb_flags, ATA0);
10808 dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE);
10809 dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE);
10810 + dc->mte_store_only[0] = EX_TBFLAG_A64(tb_flags, MTE_STORE_ONLY);
10811 + dc->mte_store_only[1] = EX_TBFLAG_A64(tb_flags, MTE0_STORE_ONLY);
10812 dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM);
10813 dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA);
10814 dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING);
target/arm/tcg/translate.h
+2
@@ -140,6 +140,8 @@ typedef struct DisasContext {
140 bool ata[2];
141 /* True if v8.5-MTE tag checks affect the PE; index with is_unpriv. */
142 bool mte_active[2];
143 + /* True if v8.5-MTE tag checks disabled for reads; index with is_unpriv. */
144 + bool mte_store_only[2];
145 /* True with v8.5-BTI and SCTLR_ELx.BT* set. */
146 bool bt;
147 /* True if any CP15 access is trapped by HSTR_EL2 */