mirror of
https://github.com/qemu/qemu.git
synced 2024-12-04 17:23:39 +08:00
target/arm: Avoid goto_tb if we're trying to exit to the main loop
Currently gen_jmp_tb() assumes that if it is called then the jump it is handling is the only reason that we might be trying to end the TB, so it will use goto_tb if it can. This is usually the case: mostly "we did something that means we must end the TB" happens on a non-branch instruction. However, there are cases where we decide early in handling an instruction that we need to end the TB and return to the main loop, and then the insn is a complex one that involves gen_jmp_tb(). For instance, for M-profile FP instructions, in gen_preserve_fp_state() which is called from vfp_access_check() we want to force an exit to the main loop if lazy state preservation is active and we are in icount mode. Make gen_jmp_tb() look at the current value of is_jmp, and only use goto_tb if the previous is_jmp was DISAS_NEXT or DISAS_TOO_MANY. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210913095440.13462-2-peter.maydell@linaro.org
This commit is contained in:
parent
dd43ac07ef
commit
84848481c3
@ -2610,8 +2610,40 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
|
||||
/* An indirect jump so that we still trigger the debug exception. */
|
||||
gen_set_pc_im(s, dest);
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
switch (s->base.is_jmp) {
|
||||
case DISAS_NEXT:
|
||||
case DISAS_TOO_MANY:
|
||||
case DISAS_NORETURN:
|
||||
/*
|
||||
* The normal case: just go to the destination TB.
|
||||
* NB: NORETURN happens if we generate code like
|
||||
* gen_brcondi(l);
|
||||
* gen_jmp();
|
||||
* gen_set_label(l);
|
||||
* gen_jmp();
|
||||
* on the second call to gen_jmp().
|
||||
*/
|
||||
gen_goto_tb(s, tbno, dest);
|
||||
break;
|
||||
case DISAS_UPDATE_NOCHAIN:
|
||||
case DISAS_UPDATE_EXIT:
|
||||
/*
|
||||
* We already decided we're leaving the TB for some other reason.
|
||||
* Avoid using goto_tb so we really do exit back to the main loop
|
||||
* and don't chain to another TB.
|
||||
*/
|
||||
gen_set_pc_im(s, dest);
|
||||
gen_goto_ptr();
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* We shouldn't be emitting code for a jump and also have
|
||||
* is_jmp set to one of the special cases like DISAS_SWI.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user