target/sparc: Implement check_align inline

Emit the exception at the end of the translation block,
so that the non-exception case can fall through.

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-10-16 13:23:15 -07:00
parent 930f1865cc
commit 186e78905a
3 changed files with 61 additions and 15 deletions

View File

@ -24,7 +24,6 @@ DEF_HELPER_FLAGS_2(tick_set_count, TCG_CALL_NO_RWG, void, ptr, i64)
DEF_HELPER_FLAGS_3(tick_get_count, TCG_CALL_NO_WG, i64, env, ptr, int)
DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
#endif
DEF_HELPER_FLAGS_3(check_align, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_1(save, void, env)
DEF_HELPER_1(restore, void, env)

View File

@ -360,6 +360,7 @@ static inline void do_check_asi(CPUSPARCState *env, int asi, uintptr_t ra)
#endif /* !CONFIG_USER_ONLY */
#endif
#if defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)
static void do_check_align(CPUSPARCState *env, target_ulong addr,
uint32_t align, uintptr_t ra)
{
@ -367,11 +368,7 @@ static void do_check_align(CPUSPARCState *env, target_ulong addr,
cpu_raise_exception_ra(env, TT_UNALIGNED, ra);
}
}
void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
{
do_check_align(env, addr, align, GETPC());
}
#endif
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
defined(DEBUG_MXCC)

View File

@ -68,6 +68,15 @@ static TCGv cpu_wim;
/* Floating point registers */
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
typedef struct DisasDelayException {
struct DisasDelayException *next;
TCGLabel *lab;
TCGv_i32 excp;
/* Saved state at parent insn. */
target_ulong pc;
target_ulong npc;
} DisasDelayException;
typedef struct DisasContext {
DisasContextBase base;
target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
@ -89,6 +98,7 @@ typedef struct DisasContext {
int fprs_dirty;
int asi;
#endif
DisasDelayException *delay_excp_list;
} DisasContext;
typedef struct {
@ -984,9 +994,38 @@ static void gen_exception(DisasContext *dc, int which)
dc->base.is_jmp = DISAS_NORETURN;
}
static void gen_check_align(TCGv addr, int mask)
static TCGLabel *delay_exceptionv(DisasContext *dc, TCGv_i32 excp)
{
gen_helper_check_align(tcg_env, addr, tcg_constant_i32(mask));
DisasDelayException *e = g_new0(DisasDelayException, 1);
e->next = dc->delay_excp_list;
dc->delay_excp_list = e;
e->lab = gen_new_label();
e->excp = excp;
e->pc = dc->pc;
/* Caller must have used flush_cond before branch. */
assert(e->npc != JUMP_PC);
e->npc = dc->npc;
return e->lab;
}
static TCGLabel *delay_exception(DisasContext *dc, int excp)
{
return delay_exceptionv(dc, tcg_constant_i32(excp));
}
static void gen_check_align(DisasContext *dc, TCGv addr, int mask)
{
TCGv t = tcg_temp_new();
TCGLabel *lab;
tcg_gen_andi_tl(t, addr, mask);
flush_cond(dc);
lab = delay_exception(dc, TT_UNALIGNED);
tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, lab);
}
static void gen_mov_pc_npc(DisasContext *dc)
@ -5019,9 +5058,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_gen_mov_tl(cpu_tmp0, cpu_src1);
}
}
gen_check_align(dc, cpu_tmp0, 3);
gen_helper_restore(tcg_env);
gen_mov_pc_npc(dc);
gen_check_align(cpu_tmp0, 3);
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
dc->npc = DYNAMIC_PC_LOOKUP;
goto jmp_insn;
@ -5044,12 +5083,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
switch (xop) {
case 0x38: /* jmpl */
{
TCGv t = gen_dest_gpr(dc, rd);
tcg_gen_movi_tl(t, dc->pc);
gen_store_gpr(dc, rd, t);
gen_check_align(dc, cpu_tmp0, 3);
gen_store_gpr(dc, rd, tcg_constant_tl(dc->pc));
gen_mov_pc_npc(dc);
gen_check_align(cpu_tmp0, 3);
gen_address_mask(dc, cpu_tmp0);
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
dc->npc = DYNAMIC_PC_LOOKUP;
@ -5060,8 +5096,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
{
if (!supervisor(dc))
goto priv_insn;
gen_check_align(dc, cpu_tmp0, 3);
gen_mov_pc_npc(dc);
gen_check_align(cpu_tmp0, 3);
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
dc->npc = DYNAMIC_PC;
gen_helper_rett(tcg_env);
@ -5643,6 +5679,7 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
DisasDelayException *e, *e_next;
bool may_lookup;
switch (dc->base.is_jmp) {
@ -5704,6 +5741,19 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
default:
g_assert_not_reached();
}
for (e = dc->delay_excp_list; e ; e = e_next) {
gen_set_label(e->lab);
tcg_gen_movi_tl(cpu_pc, e->pc);
if (e->npc % 4 == 0) {
tcg_gen_movi_tl(cpu_npc, e->npc);
}
gen_helper_raise_exception(tcg_env, e->excp);
e_next = e->next;
g_free(e);
}
}
static void sparc_tr_disas_log(const DisasContextBase *dcbase,