mirror of https://gitee.com/openkylin/qemu.git
target/openrisc: Link more translation blocks
Track direct jumps via dc->jmp_pc_imm. Use that in preference to jmp_pc when possible. Emit goto_tb in that case, and lookup_and_goto_tb otherwise. Reviewed-by: Stafford Horne <shorne@gmail.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Stafford Horne <shorne@gmail.com>
This commit is contained in:
parent
e0a369cf88
commit
8000ba56cc
|
@ -38,13 +38,16 @@
|
||||||
|
|
||||||
/* is_jmp field values */
|
/* is_jmp field values */
|
||||||
#define DISAS_EXIT DISAS_TARGET_0 /* force exit to main loop */
|
#define DISAS_EXIT DISAS_TARGET_0 /* force exit to main loop */
|
||||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
#define DISAS_JUMP DISAS_TARGET_1 /* exit via jmp_pc/jmp_pc_imm */
|
||||||
|
|
||||||
typedef struct DisasContext {
|
typedef struct DisasContext {
|
||||||
DisasContextBase base;
|
DisasContextBase base;
|
||||||
uint32_t mem_idx;
|
uint32_t mem_idx;
|
||||||
uint32_t tb_flags;
|
uint32_t tb_flags;
|
||||||
uint32_t delayed_branch;
|
uint32_t delayed_branch;
|
||||||
|
|
||||||
|
/* If not -1, jmp_pc contains this value and so is a direct jump. */
|
||||||
|
target_ulong jmp_pc_imm;
|
||||||
} DisasContext;
|
} DisasContext;
|
||||||
|
|
||||||
/* Include the auto-generated decoder. */
|
/* Include the auto-generated decoder. */
|
||||||
|
@ -160,34 +163,6 @@ static void check_ov64s(DisasContext *dc)
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
|
|
||||||
{
|
|
||||||
if (unlikely(dc->base.singlestep_enabled)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
return (dc->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
|
||||||
{
|
|
||||||
if (use_goto_tb(dc, dest)) {
|
|
||||||
tcg_gen_movi_tl(cpu_pc, dest);
|
|
||||||
tcg_gen_goto_tb(n);
|
|
||||||
tcg_gen_exit_tb(dc->base.tb, n);
|
|
||||||
} else {
|
|
||||||
tcg_gen_movi_tl(cpu_pc, dest);
|
|
||||||
if (dc->base.singlestep_enabled) {
|
|
||||||
gen_exception(dc, EXCP_DEBUG);
|
|
||||||
}
|
|
||||||
tcg_gen_exit_tb(NULL, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gen_ove_cy(DisasContext *dc)
|
static void gen_ove_cy(DisasContext *dc)
|
||||||
{
|
{
|
||||||
if (dc->tb_flags & SR_OVE) {
|
if (dc->tb_flags & SR_OVE) {
|
||||||
|
@ -621,6 +596,7 @@ static bool trans_l_j(DisasContext *dc, arg_l_j *a, uint32_t insn)
|
||||||
target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
|
target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
|
||||||
|
|
||||||
tcg_gen_movi_tl(jmp_pc, tmp_pc);
|
tcg_gen_movi_tl(jmp_pc, tmp_pc);
|
||||||
|
dc->jmp_pc_imm = tmp_pc;
|
||||||
dc->delayed_branch = 2;
|
dc->delayed_branch = 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -634,6 +610,7 @@ static bool trans_l_jal(DisasContext *dc, arg_l_jal *a, uint32_t insn)
|
||||||
/* Optimize jal being used to load the PC for PIC. */
|
/* Optimize jal being used to load the PC for PIC. */
|
||||||
if (tmp_pc != ret_pc) {
|
if (tmp_pc != ret_pc) {
|
||||||
tcg_gen_movi_tl(jmp_pc, tmp_pc);
|
tcg_gen_movi_tl(jmp_pc, tmp_pc);
|
||||||
|
dc->jmp_pc_imm = tmp_pc;
|
||||||
dc->delayed_branch = 2;
|
dc->delayed_branch = 2;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1267,6 +1244,8 @@ static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
|
||||||
dc->mem_idx = cpu_mmu_index(env, false);
|
dc->mem_idx = cpu_mmu_index(env, false);
|
||||||
dc->tb_flags = dc->base.tb->flags;
|
dc->tb_flags = dc->base.tb->flags;
|
||||||
dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
|
dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
|
||||||
|
dc->jmp_pc_imm = -1;
|
||||||
|
|
||||||
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
|
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
|
||||||
dc->base.max_insns = MIN(dc->base.max_insns, bound);
|
dc->base.max_insns = MIN(dc->base.max_insns, bound);
|
||||||
}
|
}
|
||||||
|
@ -1319,37 +1298,72 @@ static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
|
||||||
}
|
}
|
||||||
dc->base.pc_next += 4;
|
dc->base.pc_next += 4;
|
||||||
|
|
||||||
/* delay slot */
|
/* When exiting the delay slot normally, exit via jmp_pc.
|
||||||
if (dc->delayed_branch) {
|
* For DISAS_NORETURN, we have raised an exception and already exited.
|
||||||
dc->delayed_branch--;
|
* For DISAS_EXIT, we found l.rfe in a delay slot. There's nothing
|
||||||
if (!dc->delayed_branch) {
|
* in the manual saying this is illegal, but it surely it should.
|
||||||
tcg_gen_mov_tl(cpu_pc, jmp_pc);
|
* At least or1ksim overrides pcnext and ignores the branch.
|
||||||
tcg_gen_discard_tl(jmp_pc);
|
*/
|
||||||
dc->base.is_jmp = DISAS_UPDATE;
|
if (dc->delayed_branch
|
||||||
return;
|
&& --dc->delayed_branch == 0
|
||||||
}
|
&& dc->base.is_jmp == DISAS_NEXT) {
|
||||||
|
dc->base.is_jmp = DISAS_JUMP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
||||||
{
|
{
|
||||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||||
|
target_ulong jmp_dest;
|
||||||
|
|
||||||
/* If we have already exited the TB, nothing following has effect. */
|
/* If we have already exited the TB, nothing following has effect. */
|
||||||
if (dc->base.is_jmp == DISAS_NORETURN) {
|
if (dc->base.is_jmp == DISAS_NORETURN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adjust the delayed branch state for the next TB. */
|
||||||
if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) {
|
if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) {
|
||||||
tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0);
|
tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_gen_movi_tl(cpu_ppc, dc->base.pc_next - 4);
|
/* For DISAS_TOO_MANY, jump to the next insn. */
|
||||||
|
jmp_dest = dc->base.pc_next;
|
||||||
|
tcg_gen_movi_tl(cpu_ppc, jmp_dest - 4);
|
||||||
|
|
||||||
switch (dc->base.is_jmp) {
|
switch (dc->base.is_jmp) {
|
||||||
|
case DISAS_JUMP:
|
||||||
|
jmp_dest = dc->jmp_pc_imm;
|
||||||
|
if (jmp_dest == -1) {
|
||||||
|
/* The jump destination is indirect/computed; use jmp_pc. */
|
||||||
|
tcg_gen_mov_tl(cpu_pc, jmp_pc);
|
||||||
|
tcg_gen_discard_tl(jmp_pc);
|
||||||
|
if (unlikely(dc->base.singlestep_enabled)) {
|
||||||
|
gen_exception(dc, EXCP_DEBUG);
|
||||||
|
} else {
|
||||||
|
tcg_gen_lookup_and_goto_ptr();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* The jump destination is direct; use jmp_pc_imm.
|
||||||
|
However, we will have stored into jmp_pc as well;
|
||||||
|
we know now that it wasn't needed. */
|
||||||
|
tcg_gen_discard_tl(jmp_pc);
|
||||||
|
/* fallthru */
|
||||||
|
|
||||||
case DISAS_TOO_MANY:
|
case DISAS_TOO_MANY:
|
||||||
gen_goto_tb(dc, 0, dc->base.pc_next);
|
if (unlikely(dc->base.singlestep_enabled)) {
|
||||||
|
tcg_gen_movi_tl(cpu_pc, jmp_dest);
|
||||||
|
gen_exception(dc, EXCP_DEBUG);
|
||||||
|
} else if ((dc->base.pc_first ^ jmp_dest) & TARGET_PAGE_MASK) {
|
||||||
|
tcg_gen_movi_tl(cpu_pc, jmp_dest);
|
||||||
|
tcg_gen_lookup_and_goto_ptr();
|
||||||
|
} else {
|
||||||
|
tcg_gen_goto_tb(0);
|
||||||
|
tcg_gen_movi_tl(cpu_pc, jmp_dest);
|
||||||
|
tcg_gen_exit_tb(dc->base.tb, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DISAS_UPDATE:
|
|
||||||
case DISAS_EXIT:
|
case DISAS_EXIT:
|
||||||
if (unlikely(dc->base.singlestep_enabled)) {
|
if (unlikely(dc->base.singlestep_enabled)) {
|
||||||
gen_exception(dc, EXCP_DEBUG);
|
gen_exception(dc, EXCP_DEBUG);
|
||||||
|
|
Loading…
Reference in New Issue