target/arm: [tcg] Port to tb_start
Incrementally paves the way towards using the generic instruction translation loop. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> Reviewed-by: Richard Henderson <rth@twiddle.net> Reviewed-by: Alex Benneé <alex.benee@linaro.org> Message-Id: <150002364681.22386.1701754996184325808.stgit@frigg.lan> [rth: Adjust for tb_start interface change.] Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
5c03990665
commit
b14768544f
|
@ -11893,6 +11893,49 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase,
|
|||
return max_insns;
|
||||
}
|
||||
|
||||
static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
/* A note on handling of the condexec (IT) bits:
|
||||
*
|
||||
* We want to avoid the overhead of having to write the updated condexec
|
||||
* bits back to the CPUARMState for every instruction in an IT block. So:
|
||||
* (1) if the condexec bits are not already zero then we write
|
||||
* zero back into the CPUARMState now. This avoids complications trying
|
||||
* to do it at the end of the block. (For example if we don't do this
|
||||
* it's hard to identify whether we can safely skip writing condexec
|
||||
* at the end of the TB, which we definitely want to do for the case
|
||||
* where a TB doesn't do anything with the IT state at all.)
|
||||
* (2) if we are going to leave the TB then we call gen_set_condexec()
|
||||
* which will write the correct value into CPUARMState if zero is wrong.
|
||||
* This is done both for leaving the TB at the end, and for leaving
|
||||
* it because of an exception we know will happen, which is done in
|
||||
* gen_exception_insn(). The latter is necessary because we need to
|
||||
* leave the TB with the PC/IT state just prior to execution of the
|
||||
* instruction which caused the exception.
|
||||
* (3) if we leave the TB unexpectedly (eg a data abort on a load)
|
||||
* then the CPUARMState will be wrong and we need to reset it.
|
||||
* This is handled in the same way as restoration of the
|
||||
* PC in these situations; we save the value of the condexec bits
|
||||
* for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
|
||||
* then uses this to restore them after an exception.
|
||||
*
|
||||
* Note that there are no instructions which can read the condexec
|
||||
* bits, and none which can write non-static values to them, so
|
||||
* we don't need to care about whether CPUARMState is correct in the
|
||||
* middle of a TB.
|
||||
*/
|
||||
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
if (dc->condexec_mask || dc->condexec_cond) {
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, 0);
|
||||
store_cpu_field(tmp, condexec_bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
{
|
||||
|
@ -11932,45 +11975,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
gen_tb_start(tb);
|
||||
|
||||
tcg_clear_temp_count();
|
||||
arm_tr_tb_start(&dc->base, cs);
|
||||
|
||||
/* A note on handling of the condexec (IT) bits:
|
||||
*
|
||||
* We want to avoid the overhead of having to write the updated condexec
|
||||
* bits back to the CPUARMState for every instruction in an IT block. So:
|
||||
* (1) if the condexec bits are not already zero then we write
|
||||
* zero back into the CPUARMState now. This avoids complications trying
|
||||
* to do it at the end of the block. (For example if we don't do this
|
||||
* it's hard to identify whether we can safely skip writing condexec
|
||||
* at the end of the TB, which we definitely want to do for the case
|
||||
* where a TB doesn't do anything with the IT state at all.)
|
||||
* (2) if we are going to leave the TB then we call gen_set_condexec()
|
||||
* which will write the correct value into CPUARMState if zero is wrong.
|
||||
* This is done both for leaving the TB at the end, and for leaving
|
||||
* it because of an exception we know will happen, which is done in
|
||||
* gen_exception_insn(). The latter is necessary because we need to
|
||||
* leave the TB with the PC/IT state just prior to execution of the
|
||||
* instruction which caused the exception.
|
||||
* (3) if we leave the TB unexpectedly (eg a data abort on a load)
|
||||
* then the CPUARMState will be wrong and we need to reset it.
|
||||
* This is handled in the same way as restoration of the
|
||||
* PC in these situations; we save the value of the condexec bits
|
||||
* for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
|
||||
* then uses this to restore them after an exception.
|
||||
*
|
||||
* Note that there are no instructions which can read the condexec
|
||||
* bits, and none which can write non-static values to them, so
|
||||
* we don't need to care about whether CPUARMState is correct in the
|
||||
* middle of a TB.
|
||||
*/
|
||||
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
if (dc->condexec_mask || dc->condexec_cond)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, 0);
|
||||
store_cpu_field(tmp, condexec_bits);
|
||||
}
|
||||
do {
|
||||
dc->base.num_insns++;
|
||||
dc->insn_start_idx = tcg_op_buf_count();
|
||||
|
|
Loading…
Reference in a new issue