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. Buglink: https://bugs.launchpad.net/bugs/1912065 Tested-by: BALATON Zoltan <balaton@eik.bme.hu> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
653b87eb36
commit
ae30e86661
@ -1926,11 +1926,17 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
ti = profile_getclock();
|
||||
#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_ctx->cpu = env_cpu(env);
|
||||
gen_intermediate_code(cpu, tb, max_insns);
|
||||
tcg_ctx->cpu = NULL;
|
||||
max_insns = tb->icount;
|
||||
|
||||
trace_translate_block(tb, tb->pc, tb->tc.ptr);
|
||||
|
||||
@ -1955,6 +1961,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
|
||||
gen_code_size = tcg_gen_code(tcg_ctx, tb);
|
||||
if (unlikely(gen_code_size < 0)) {
|
||||
error_return:
|
||||
switch (gen_code_size) {
|
||||
case -1:
|
||||
/*
|
||||
@ -1966,6 +1973,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
* flush the TBs, allocate a new TB, re-initialize it per
|
||||
* 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;
|
||||
|
||||
case -2:
|
||||
@ -1978,9 +1988,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
* Try again with half as many insns as we attempted this time.
|
||||
* If a single insn overflows, there's a bug somewhere...
|
||||
*/
|
||||
max_insns = tb->icount;
|
||||
assert(max_insns > 1);
|
||||
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;
|
||||
|
||||
default:
|
||||
|
@ -680,6 +680,9 @@ struct TCGContext {
|
||||
|
||||
uint16_t gen_insn_end_off[TCG_MAX_INSNS];
|
||||
target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
|
||||
|
||||
/* Exit to translator on overflow. */
|
||||
sigjmp_buf jmp_trans;
|
||||
};
|
||||
|
||||
static inline bool temp_readonly(TCGTemp *ts)
|
||||
|
11
tcg/tcg.c
11
tcg/tcg.c
@ -1205,18 +1205,23 @@ void tcg_func_start(TCGContext *s)
|
||||
QSIMPLEQ_INIT(&s->labels);
|
||||
}
|
||||
|
||||
static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
|
||||
static TCGTemp *tcg_temp_alloc(TCGContext *s)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
static inline TCGTemp *tcg_global_alloc(TCGContext *s)
|
||||
static TCGTemp *tcg_global_alloc(TCGContext *s)
|
||||
{
|
||||
TCGTemp *ts;
|
||||
|
||||
tcg_debug_assert(s->nb_globals == s->nb_temps);
|
||||
tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS);
|
||||
s->nb_globals++;
|
||||
ts = tcg_temp_alloc(s);
|
||||
ts->kind = TEMP_GLOBAL;
|
||||
|
Loading…
Reference in New Issue
Block a user