target/m68k: add a mechanism to automatically free TCGv

SRC_EA() and gen_extend() can return either a temporary
TCGv or a memory allocated one. Mark them when they are
allocated, and free them automatically at end of the
instruction translation.

We want to free locally allocated TCGv to avoid
overflow in sequence like:

0xc00ae406: movel %fp@(-132),%fp@(-268)
0xc00ae40c: movel %fp@(-128),%fp@(-264)
0xc00ae412: movel %fp@(-20),%fp@(-212)
0xc00ae418: movel %fp@(-16),%fp@(-208)
0xc00ae41e: movel %fp@(-60),%fp@(-220)
0xc00ae424: movel %fp@(-56),%fp@(-216)
0xc00ae42a: movel %fp@(-124),%fp@(-252)
0xc00ae430: movel %fp@(-120),%fp@(-248)
0xc00ae436: movel %fp@(-12),%fp@(-260)
0xc00ae43c: movel %fp@(-8),%fp@(-256)
0xc00ae442: movel %fp@(-52),%fp@(-276)
0xc00ae448: movel %fp@(-48),%fp@(-272)
...

That can fill a lot of TCGv entries in a sequence,
especially since 15fa08f845 ("tcg: Dynamically allocate TCGOps")
we have no limit to fill the TCGOps cache and we can fill
the entire TCG variables array and overflow it.

Backports commit ecc207d2fc1d45fabb16c38742a6675a7ba56cbc from qemu
This commit is contained in:
Laurent Vivier 2018-03-20 14:30:51 -04:00 committed by Lioncash
parent 30d878a0ef
commit c133a7b306
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -103,11 +103,37 @@ typedef struct DisasContext {
int done_mac; int done_mac;
int writeback_mask; int writeback_mask;
TCGv writeback[8]; TCGv writeback[8];
#define MAX_TO_RELEASE 8
int release_count;
TCGv release[MAX_TO_RELEASE];
// Unicorn engine // Unicorn engine
struct uc_struct *uc; struct uc_struct *uc;
} DisasContext; } DisasContext;
static void init_release_array(DisasContext *s)
{
#ifdef CONFIG_DEBUG_TCG
memset(s->release, 0, sizeof(s->release));
#endif
s->release_count = 0;
}
static void do_release(DisasContext *s)
{
int i;
for (i = 0; i < s->release_count; i++) {
tcg_temp_free(s->uc->tcg_ctx, s->release[i]);
}
init_release_array(s);
}
static TCGv mark_to_release(DisasContext *s, TCGv tmp)
{
g_assert(s->release_count < MAX_TO_RELEASE);
return s->release[s->release_count++] = tmp;
}
static TCGv get_areg(DisasContext *s, unsigned regno) static TCGv get_areg(DisasContext *s, unsigned regno)
{ {
TCGContext *tcg_ctx = s->uc->tcg_ctx; TCGContext *tcg_ctx = s->uc->tcg_ctx;
@ -352,7 +378,8 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
gen_store(s, opsize, addr, val, index); gen_store(s, opsize, addr, val, index);
return tcg_ctx->store_dummy; return tcg_ctx->store_dummy;
} else { } else {
return gen_load(s, opsize, addr, what == EA_LOADS, index); return mark_to_release(s, gen_load(s, opsize, addr,
what == EA_LOADS, index));
} }
} }
@ -446,7 +473,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
} else { } else {
bd = 0; bd = 0;
} }
tmp = tcg_temp_new(tcg_ctx); tmp = mark_to_release(s, tcg_temp_new(tcg_ctx));
if ((ext & 0x44) == 0) { if ((ext & 0x44) == 0) {
/* pre-index */ /* pre-index */
add = gen_addr_index(s, ext, tmp); add = gen_addr_index(s, ext, tmp);
@ -456,7 +483,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
if ((ext & 0x80) == 0) { if ((ext & 0x80) == 0) {
/* base not suppressed */ /* base not suppressed */
if (IS_NULL_QREG(base)) { if (IS_NULL_QREG(base)) {
base = tcg_const_i32(tcg_ctx, offset + bd); base = mark_to_release(s, tcg_const_i32(tcg_ctx, offset + bd));
bd = 0; bd = 0;
} }
if (!IS_NULL_QREG(add)) { if (!IS_NULL_QREG(add)) {
@ -472,11 +499,11 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
add = tmp; add = tmp;
} }
} else { } else {
add = tcg_const_i32(tcg_ctx, bd); add = mark_to_release(s, tcg_const_i32(tcg_ctx, bd));
} }
if ((ext & 3) != 0) { if ((ext & 3) != 0) {
/* memory indirect */ /* memory indirect */
base = gen_load(s, OS_LONG, add, 0, IS_USER(s)); base = mark_to_release(s, gen_load(s, OS_LONG, add, 0, IS_USER(s)));
if ((ext & 0x44) == 4) { if ((ext & 0x44) == 4) {
add = gen_addr_index(s, ext, tmp); add = gen_addr_index(s, ext, tmp);
tcg_gen_add_i32(tcg_ctx, tmp, add, base); tcg_gen_add_i32(tcg_ctx, tmp, add, base);
@ -501,7 +528,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
} }
} else { } else {
/* brief extension word format */ /* brief extension word format */
tmp = tcg_temp_new(tcg_ctx); tmp = mark_to_release(s, tcg_temp_new(tcg_ctx));
add = gen_addr_index(s, ext, tmp); add = gen_addr_index(s, ext, tmp);
if (!IS_NULL_QREG(base)) { if (!IS_NULL_QREG(base)) {
tcg_gen_add_i32(tcg_ctx, tmp, add, base); tcg_gen_add_i32(tcg_ctx, tmp, add, base);
@ -635,7 +662,7 @@ static inline TCGv gen_extend(DisasContext *s, TCGv val, int opsize, int sign)
if (opsize == OS_LONG) { if (opsize == OS_LONG) {
tmp = val; tmp = val;
} else { } else {
tmp = tcg_temp_new(tcg_ctx); tmp = mark_to_release(s, tcg_temp_new(tcg_ctx));
gen_ext(s, tmp, val, opsize, sign); gen_ext(s, tmp, val, opsize, sign);
} }
@ -766,7 +793,7 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
return tcg_ctx->NULL_QREG; return tcg_ctx->NULL_QREG;
} }
reg = get_areg(s, reg0); reg = get_areg(s, reg0);
tmp = tcg_temp_new(tcg_ctx); tmp = mark_to_release(s, tcg_temp_new(tcg_ctx));
if (reg0 == 7 && opsize == OS_BYTE && if (reg0 == 7 && opsize == OS_BYTE &&
m68k_feature(s->env, M68K_FEATURE_M68000)) { m68k_feature(s->env, M68K_FEATURE_M68000)) {
tcg_gen_subi_i32(tcg_ctx, tmp, reg, 2); tcg_gen_subi_i32(tcg_ctx, tmp, reg, 2);
@ -776,7 +803,7 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
return tmp; return tmp;
case 5: /* Indirect displacement. */ case 5: /* Indirect displacement. */
reg = get_areg(s, reg0); reg = get_areg(s, reg0);
tmp = tcg_temp_new(tcg_ctx); tmp = mark_to_release(s, tcg_temp_new(tcg_ctx));
ext = read_im16(env, s); ext = read_im16(env, s);
tcg_gen_addi_i32(tcg_ctx, tmp, reg, (int16_t)ext); tcg_gen_addi_i32(tcg_ctx, tmp, reg, (int16_t)ext);
return tmp; return tmp;
@ -787,14 +814,14 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
switch (reg0) { switch (reg0) {
case 0: /* Absolute short. */ case 0: /* Absolute short. */
offset = (int16_t)read_im16(env, s); offset = (int16_t)read_im16(env, s);
return tcg_const_i32(tcg_ctx, offset); return mark_to_release(s, tcg_const_i32(tcg_ctx, offset));
case 1: /* Absolute long. */ case 1: /* Absolute long. */
offset = read_im32(env, s); offset = read_im32(env, s);
return tcg_const_i32(tcg_ctx, offset); return mark_to_release(s, tcg_const_i32(tcg_ctx, offset));
case 2: /* pc displacement */ case 2: /* pc displacement */
offset = s->pc; offset = s->pc;
offset += (int16_t)read_im16(env, s); offset += (int16_t)read_im16(env, s);
return tcg_const_i32(tcg_ctx, offset); return mark_to_release(s, tcg_const_i32(tcg_ctx, offset));
case 3: /* pc index+displacement. */ case 3: /* pc index+displacement. */
return gen_lea_indexed(env, s, tcg_ctx->NULL_QREG); return gen_lea_indexed(env, s, tcg_ctx->NULL_QREG);
case 4: /* Immediate. */ case 4: /* Immediate. */
@ -921,7 +948,7 @@ static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
return tcg_const_i32(tcg_ctx, offset); return mark_to_release(s, tcg_const_i32(tcg_ctx, offset));
default: default:
return tcg_ctx->NULL_QREG; return tcg_ctx->NULL_QREG;
} }
@ -6271,6 +6298,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
uint16_t insn = read_im16(env, s); uint16_t insn = read_im16(env, s);
((disas_proc)tcg_ctx->opcode_table[insn])(env, s, insn); ((disas_proc)tcg_ctx->opcode_table[insn])(env, s, insn);
do_writebacks(s); do_writebacks(s);
do_release(s);
} }
/* generate intermediate code for basic block 'tb'. */ /* generate intermediate code for basic block 'tb'. */
@ -6330,6 +6358,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
env->uc->size_arg = -1; env->uc->size_arg = -1;
} }
init_release_array(dc);
gen_tb_start(tcg_ctx, tb); gen_tb_start(tcg_ctx, tb);
do { do {
pc_offset = dc->pc - pc_start; pc_offset = dc->pc - pc_start;