12fa73f2b6
Consider this case: t:inc ecx, inc edx, jmp t It would generate exactly one block and TB chain will generate an inline jump. If we don't check exit at the entry of the block, we will never be terminated. This test case is recorded in the commit message since it's a bit painful to write multithread related code that builds on all platforms.
63 lines
1.8 KiB
C
63 lines
1.8 KiB
C
#ifndef GEN_ICOUNT_H
|
|
#define GEN_ICOUNT_H
|
|
|
|
#include "qemu/timer.h"
|
|
|
|
/* Helpers for instruction counting code generation. */
|
|
|
|
static inline void gen_io_start(TCGContext *tcg_ctx)
|
|
{
|
|
TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 1);
|
|
tcg_gen_st_i32(tcg_ctx, tmp, tcg_ctx->cpu_env,
|
|
offsetof(ArchCPU, parent_obj.can_do_io) -
|
|
offsetof(ArchCPU, env));
|
|
tcg_temp_free_i32(tcg_ctx, tmp);
|
|
}
|
|
|
|
/*
|
|
* cpu->can_do_io is cleared automatically at the beginning of
|
|
* each translation block. The cost is minimal and only paid
|
|
* for -icount, plus it would be very easy to forget doing it
|
|
* in the translator. Therefore, backends only need to call
|
|
* gen_io_start.
|
|
*/
|
|
static inline void gen_io_end(TCGContext *tcg_ctx)
|
|
{
|
|
TCGv_i32 tmp = tcg_const_i32(tcg_ctx, 0);
|
|
tcg_gen_st_i32(tcg_ctx, tmp, tcg_ctx->cpu_env,
|
|
offsetof(ArchCPU, parent_obj.can_do_io) -
|
|
offsetof(ArchCPU, env));
|
|
tcg_temp_free_i32(tcg_ctx, tmp);
|
|
}
|
|
|
|
static inline void gen_tb_start(TCGContext *tcg_ctx, TranslationBlock *tb)
|
|
{
|
|
TCGv_i32 count;
|
|
|
|
tcg_ctx->exitreq_label = gen_new_label(tcg_ctx);
|
|
|
|
count = tcg_temp_new_i32(tcg_ctx);
|
|
|
|
tcg_gen_ld_i32(tcg_ctx, count, tcg_ctx->cpu_env,
|
|
offsetof(ArchCPU, neg.icount_decr.u32) -
|
|
offsetof(ArchCPU, env));
|
|
|
|
tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_LT, count, 0, tcg_ctx->exitreq_label);
|
|
|
|
tcg_temp_free_i32(tcg_ctx, count);
|
|
}
|
|
|
|
static inline void gen_tb_end(TCGContext *tcg_ctx, TranslationBlock *tb, int num_insns)
|
|
{
|
|
if (tb_cflags(tb) & CF_USE_ICOUNT) {
|
|
/* Update the num_insn immediate parameter now that we know
|
|
* the actual insn count. */
|
|
tcg_set_insn_param(tcg_ctx->icount_start_insn, 1, num_insns);
|
|
}
|
|
|
|
gen_set_label(tcg_ctx, tcg_ctx->exitreq_label);
|
|
tcg_gen_exit_tb(tcg_ctx, tb, TB_EXIT_REQUESTED);
|
|
}
|
|
|
|
#endif
|