We can use tcg_gen_goto_jc_i64 for direct or indirect branches, where flags are known to not change. We can use tcg_gen_goto_jc3_i64 in gen_call_pal where flags are known to change in a very specific way.
Introduce DISAS_PC_STALE_NOJC as a case where flags are changing in an unpredictable way and must therefore use the runtime lookup. Introduce DISAS_PC_STALE_NOCHAIN as a case where we must return to the main loop. Remove DISAS_PC_STALE and use DISAS_TOO_MANY instead, as they wind up having the same semantics. End the translation block when setting PS or FEN, as they represent changes in tbflags. This avoids a subsequent insn incorrectly chaining via the jump cache and failing the assert. Signed-off-by: Richard Henderson <[email protected]> --- target/alpha/translate.c | 60 ++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 6f18b8d1af6..ecb4ac4b023 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -80,9 +80,10 @@ struct DisasContext { /* Target-specific return values from translate_one, indicating the state of the TB. Note that DISAS_NEXT indicates that we are not exiting the TB. */ -#define DISAS_PC_UPDATED_NOCHAIN DISAS_TARGET_0 -#define DISAS_PC_UPDATED DISAS_TARGET_1 -#define DISAS_PC_STALE DISAS_TARGET_2 +#define DISAS_PC_UPDATED DISAS_TARGET_0 +#define DISAS_PC_STALE_NOJC DISAS_TARGET_1 +#define DISAS_PC_STALE_NOCHAIN DISAS_TARGET_2 +#define DISAS_PC_UPDATED_NOCHAIN DISAS_TARGET_3 /* global register indexes */ static TCGv_i64 cpu_std_ir[31]; @@ -449,7 +450,7 @@ static void gen_goto_tb(DisasContext *ctx, unsigned tb_slot_idx, int32_t disp) tcg_gen_exit_tb(ctx->base.tb, tb_slot_idx); } else { gen_pc_disp(ctx, cpu_pc, disp); - tcg_gen_lookup_and_goto_ptr(); + tcg_gen_goto_jc_i64(cpu_pc); } } @@ -1096,8 +1097,7 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) } /* Allow interrupts to be recognized right away. */ - gen_pc_disp(ctx, cpu_pc, 0); - return DISAS_PC_UPDATED_NOCHAIN; + return DISAS_PC_STALE_NOCHAIN; case 0x36: /* RDPS */ @@ -1148,6 +1148,7 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) tcg_gen_ori_i64(tmp, tmp, 1); } else { st_flag_byte(tcg_constant_i64(1), ENV_FLAG_PAL_SHIFT); + ctx->tbflags = deposit32(ctx->tbflags, ENV_FLAG_PAL_SHIFT, 8, 1); } tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUAlphaState, exc_addr)); @@ -1156,7 +1157,9 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode) palcode & 0x80 ? 0x2000 + (palcode - 0x80) * 64 : 0x1000 + palcode * 64); - return DISAS_PC_UPDATED; + + tcg_gen_goto_jc3_i64(cpu_pc, load_zero(ctx), ctx->tbflags); + return DISAS_NORETURN; } #endif } @@ -1191,8 +1194,7 @@ static int cpu_pr_data(int pr) static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv_i64 va, int regno) { - void (*helper)(TCGv_i64); - int data; + int data, ret = DISAS_NEXT; switch (regno) { case 32 ... 39: @@ -1202,17 +1204,16 @@ static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv_i64 va, int regno) break; case 250: /* WALLTIME */ - helper = gen_helper_get_walltime; - goto do_helper; - case 249: /* VMTIME */ - helper = gen_helper_get_vmtime; - do_helper: if (translator_io_start(&ctx->base)) { - helper(va); - return DISAS_PC_STALE; - } else { - helper(va); + ret = DISAS_TOO_MANY; /* i/o insns must be last in tb */ } + gen_helper_get_walltime(va); + break; + case 249: /* VMTIME */ + if (translator_io_start(&ctx->base)) { + ret = DISAS_TOO_MANY; /* i/o insns must be last in tb */ + } + gen_helper_get_vmtime(va); break; case 0: /* PS */ @@ -1236,7 +1237,7 @@ static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv_i64 va, int regno) break; } - return DISAS_NEXT; + return ret; } static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv_i64 vb, int regno) @@ -1264,12 +1265,12 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv_i64 vb, int regno) case 252: /* HALT */ gen_helper_halt(vb); - return DISAS_PC_STALE; + return DISAS_PC_STALE_NOCHAIN; case 251: /* ALARM */ if (translator_io_start(&ctx->base)) { - ret = DISAS_PC_STALE; + ret = DISAS_TOO_MANY; /* i/o insns must be last in tb */ } gen_helper_set_alarm(tcg_env, vb); break; @@ -1287,10 +1288,11 @@ static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv_i64 vb, int regno) case 0: /* PS */ st_flag_byte(vb, ENV_FLAG_PS_SHIFT); - break; + return DISAS_PC_STALE_NOJC; /* flags updated */ + case 1: /* FEN */ st_flag_byte(vb, ENV_FLAG_FEN_SHIFT); - break; + return DISAS_PC_STALE_NOJC; /* flags updated */ default: /* The basic registers are data only, and unknown registers @@ -2289,7 +2291,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) /* RPCC */ va = dest_gpr(ctx, ra); if (translator_io_start(&ctx->base)) { - ret = DISAS_PC_STALE; + ret = DISAS_TOO_MANY; /* i/o insns must be last in tb */ } gen_helper_load_pcc(va, tcg_env); break; @@ -2905,12 +2907,16 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_goto_tb(ctx, 0, 0); break; - case DISAS_PC_STALE: - gen_pc_disp(ctx, cpu_pc, 0); - /* FALLTHRU */ case DISAS_PC_UPDATED: + tcg_gen_goto_jc_i64(cpu_pc); + break; + case DISAS_PC_STALE_NOJC: + gen_pc_disp(ctx, cpu_pc, 0); tcg_gen_lookup_and_goto_ptr(); break; + case DISAS_PC_STALE_NOCHAIN: + gen_pc_disp(ctx, cpu_pc, 0); + /* fallthru */ case DISAS_PC_UPDATED_NOCHAIN: tcg_gen_exit_tb(NULL, 0); break; -- 2.53.0
