tcg: Restart code generation when we run out of temps

Some large translation blocks can generate so many unique
constants that we run out of temps to hold them. In this
case, longjmp back to the start of code generation and
restart with a smaller translation block.

Backports ae30e86661b0f48562cd95918d37cbeec5d0226
This commit is contained in:
Richard Henderson 2021-03-04 15:37:02 -05:00 committed by Lioncash
parent 554a304d3d
commit 5fb8ab10eb
3 changed files with 25 additions and 4 deletions

View file

@ -1372,11 +1372,17 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
ti = profile_getclock(); ti = profile_getclock();
#endif #endif
gen_code_size = sigsetjmp(tcg_ctx->jmp_trans, 0);
if (unlikely(gen_code_size != 0)) {
goto error_return;
}
tcg_func_start(tcg_ctx); tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env); tcg_ctx->cpu = env_cpu(env);
gen_intermediate_code(cpu, tb, max_insns); gen_intermediate_code(cpu, tb, max_insns);
tcg_ctx->cpu = NULL; tcg_ctx->cpu = NULL;
max_insns = tb->icount;
// Unicorn: FIXME: Needs to be amended to work with new TCG // Unicorn: FIXME: Needs to be amended to work with new TCG
#if 0 #if 0
@ -1413,6 +1419,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
gen_code_size = tcg_gen_code(tcg_ctx, tb); gen_code_size = tcg_gen_code(tcg_ctx, tb);
if (unlikely(gen_code_size < 0)) { if (unlikely(gen_code_size < 0)) {
error_return:
switch (gen_code_size) { switch (gen_code_size) {
case -1: case -1:
/* /*
@ -1424,6 +1431,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
* flush the TBs, allocate a new TB, re-initialize it per * flush the TBs, allocate a new TB, re-initialize it per
* above, and re-do the actual code generation. * above, and re-do the actual code generation.
*/ */
qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT,
"Restarting code generation for "
"code_gen_buffer overflow\n");
goto buffer_overflow; goto buffer_overflow;
case -2: case -2:
@ -1436,9 +1446,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
* Try again with half as many insns as we attempted this time. * Try again with half as many insns as we attempted this time.
* If a single insn overflows, there's a bug somewhere... * If a single insn overflows, there's a bug somewhere...
*/ */
max_insns = tb->icount;
assert(max_insns > 1); assert(max_insns > 1);
max_insns /= 2; max_insns /= 2;
qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT,
"Restarting code generation with "
"smaller translation block (max %d insns)\n",
max_insns);
goto tb_overflow; goto tb_overflow;
default: default:

View file

@ -543,18 +543,23 @@ void tcg_func_start(TCGContext *s)
QSIMPLEQ_INIT(&s->labels); QSIMPLEQ_INIT(&s->labels);
} }
static inline TCGTemp *tcg_temp_alloc(TCGContext *s) static TCGTemp *tcg_temp_alloc(TCGContext *s)
{ {
int n = s->nb_temps++; int n = s->nb_temps++;
tcg_debug_assert(n < TCG_MAX_TEMPS);
if (n >= TCG_MAX_TEMPS) {
/* Signal overflow, starting over with fewer guest insns. */
siglongjmp(s->jmp_trans, -2);
}
return memset(&s->temps[n], 0, sizeof(TCGTemp)); return memset(&s->temps[n], 0, sizeof(TCGTemp));
} }
static inline TCGTemp *tcg_global_alloc(TCGContext *s) static TCGTemp *tcg_global_alloc(TCGContext *s)
{ {
TCGTemp *ts; TCGTemp *ts;
tcg_debug_assert(s->nb_globals == s->nb_temps); tcg_debug_assert(s->nb_globals == s->nb_temps);
tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
s->nb_globals++; s->nb_globals++;
ts = tcg_temp_alloc(s); ts = tcg_temp_alloc(s);
ts->kind = TEMP_GLOBAL; ts->kind = TEMP_GLOBAL;

View file

@ -755,6 +755,9 @@ struct TCGContext {
uint16_t gen_insn_end_off[TCG_MAX_INSNS]; uint16_t gen_insn_end_off[TCG_MAX_INSNS];
target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS]; target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
/* Exit to translator on overflow. */
sigjmp_buf jmp_trans;
// Unicorn engine variables // Unicorn engine variables
struct uc_struct *uc; struct uc_struct *uc;
/* qemu/target-i386/translate.c: global register indexes */ /* qemu/target-i386/translate.c: global register indexes */