target/sparc: Introduce DYNAMIC_PC_LOOKUP

Create a new artificial "next pc" which also indicates
that nothing has changed within the cpu state which
requires returning to the main loop.

Pipe this new value though all pc/npc checks.
Do not produce this new value yet.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230628071202.230991-5-richard.henderson@linaro.org>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
This commit is contained in:
Richard Henderson 2023-06-28 09:11:58 +02:00 committed by Mark Cave-Ayland
parent 0c2e96c170
commit 633c42834c
1 changed files with 103 additions and 44 deletions

View File

@ -37,9 +37,12 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
#define DYNAMIC_PC 1 /* dynamic pc value */
#define JUMP_PC 2 /* dynamic pc value which takes only two values
according to jump_pc[T2] */
/* Dynamic PC, must exit to main loop. */
#define DYNAMIC_PC 1
/* Dynamic PC, one of two values according to jump_pc[T2]. */
#define JUMP_PC 2
/* Dynamic PC, may lookup next TB. */
#define DYNAMIC_PC_LOOKUP 3
#define DISAS_EXIT DISAS_TARGET_0
@ -901,22 +904,25 @@ static void gen_branch_n(DisasContext *dc, target_ulong pc1)
{
target_ulong npc = dc->npc;
if (likely(npc != DYNAMIC_PC)) {
if (npc & 3) {
switch (npc) {
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
tcg_gen_mov_tl(cpu_pc, cpu_npc);
tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc,
cpu_cond, tcg_constant_tl(0),
tcg_constant_tl(pc1), cpu_npc);
dc->pc = npc;
break;
default:
g_assert_not_reached();
}
} else {
dc->pc = npc;
dc->jump_pc[0] = pc1;
dc->jump_pc[1] = npc + 4;
dc->npc = JUMP_PC;
} else {
TCGv t, z;
tcg_gen_mov_tl(cpu_pc, cpu_npc);
tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
t = tcg_constant_tl(pc1);
z = tcg_constant_tl(0);
tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, z, t, cpu_npc);
dc->pc = DYNAMIC_PC;
}
}
@ -941,10 +947,19 @@ static void flush_cond(DisasContext *dc)
static void save_npc(DisasContext *dc)
{
if (dc->npc == JUMP_PC) {
gen_generic_branch(dc);
dc->npc = DYNAMIC_PC;
} else if (dc->npc != DYNAMIC_PC) {
if (dc->npc & 3) {
switch (dc->npc) {
case JUMP_PC:
gen_generic_branch(dc);
dc->npc = DYNAMIC_PC;
break;
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
break;
default:
g_assert_not_reached();
}
} else {
tcg_gen_movi_tl(cpu_npc, dc->npc);
}
}
@ -977,13 +992,21 @@ static void gen_check_align(TCGv addr, int mask)
static void gen_mov_pc_npc(DisasContext *dc)
{
if (dc->npc == JUMP_PC) {
gen_generic_branch(dc);
tcg_gen_mov_tl(cpu_pc, cpu_npc);
dc->pc = DYNAMIC_PC;
} else if (dc->npc == DYNAMIC_PC) {
tcg_gen_mov_tl(cpu_pc, cpu_npc);
dc->pc = DYNAMIC_PC;
if (dc->npc & 3) {
switch (dc->npc) {
case JUMP_PC:
gen_generic_branch(dc);
tcg_gen_mov_tl(cpu_pc, cpu_npc);
dc->pc = DYNAMIC_PC;
break;
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
tcg_gen_mov_tl(cpu_pc, cpu_npc);
dc->pc = dc->npc;
break;
default:
g_assert_not_reached();
}
} else {
dc->pc = dc->npc;
}
@ -5501,13 +5524,21 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
break;
}
/* default case for non jump instructions */
if (dc->npc == DYNAMIC_PC) {
dc->pc = DYNAMIC_PC;
gen_op_next_insn();
} else if (dc->npc == JUMP_PC) {
/* we can do a static jump */
gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
dc->base.is_jmp = DISAS_NORETURN;
if (dc->npc & 3) {
switch (dc->npc) {
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
dc->pc = dc->npc;
gen_op_next_insn();
break;
case JUMP_PC:
/* we can do a static jump */
gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
dc->base.is_jmp = DISAS_NORETURN;
break;
default:
g_assert_not_reached();
}
} else {
dc->pc = dc->npc;
dc->npc = dc->npc + 4;
@ -5578,13 +5609,23 @@ static void sparc_tr_tb_start(DisasContextBase *db, CPUState *cs)
static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
target_ulong npc = dc->npc;
if (dc->npc == JUMP_PC) {
assert(dc->jump_pc[1] == dc->pc + 4);
tcg_gen_insn_start(dc->pc, dc->jump_pc[0] | JUMP_PC);
} else {
tcg_gen_insn_start(dc->pc, dc->npc);
if (npc & 3) {
switch (npc) {
case JUMP_PC:
assert(dc->jump_pc[1] == dc->pc + 4);
npc = dc->jump_pc[0] | JUMP_PC;
break;
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
npc = DYNAMIC_PC;
break;
default:
g_assert_not_reached();
}
}
tcg_gen_insn_start(dc->pc, npc);
}
static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
@ -5608,19 +5649,37 @@ 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);
bool may_lookup;
switch (dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
if (dc->pc != DYNAMIC_PC &&
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
if (((dc->pc | dc->npc) & 3) == 0) {
/* static PC and NPC: we can use direct chaining */
gen_goto_tb(dc, 0, dc->pc, dc->npc);
} else {
if (dc->pc != DYNAMIC_PC) {
tcg_gen_movi_tl(cpu_pc, dc->pc);
break;
}
if (dc->pc & 3) {
switch (dc->pc) {
case DYNAMIC_PC_LOOKUP:
may_lookup = true;
break;
case DYNAMIC_PC:
may_lookup = false;
break;
default:
g_assert_not_reached();
}
save_npc(dc);
} else {
tcg_gen_movi_tl(cpu_pc, dc->pc);
may_lookup = true;
}
save_npc(dc);
if (may_lookup) {
tcg_gen_lookup_and_goto_ptr();
} else {
tcg_gen_exit_tb(NULL, 0);
}
break;