tcg: Restart TB generation after relocation overflow

If the TB generates too much code, such that backend relocations
overflow, try again with a smaller TB. In support of this, move
relocation processing from a random place within tcg_out_op, in
the handling of branch opcodes, to a new function at the end of
tcg_gen_code.

This is not a complete solution, as there are additional relocs
generated for out-of-line ldst handling and constant pools.

Backports commit 7ecd02a06f8f4c0bbf872ecc15e37035b7e1df5f from qemu
This commit is contained in:
Richard Henderson 2019-04-30 09:58:44 -04:00 committed by Lioncash
parent 434b3ab9ec
commit 45315fd8ef
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
2 changed files with 40 additions and 39 deletions

View file

@ -211,37 +211,18 @@ static QEMU_UNUSED_FUNC inline void tcg_patch64(tcg_insn_unit *p,
static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
TCGLabel *l, intptr_t addend) TCGLabel *l, intptr_t addend)
{ {
TCGRelocation *r; TCGRelocation *r = tcg_malloc(s, sizeof(TCGRelocation));
if (l->has_value) { r->type = type;
/* FIXME: This may break relocations on RISC targets that r->ptr = code_ptr;
modify instruction fields in place. The caller may not have r->addend = addend;
written the initial value. */ QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
bool ok = patch_reloc(code_ptr, type, l->u.value, addend);
tcg_debug_assert(ok);
} else {
/* add a new relocation entry */
r = tcg_malloc(s, sizeof(TCGRelocation));
r->type = type;
r->ptr = code_ptr;
r->addend = addend;
r->next = l->u.first_reloc;
l->u.first_reloc = r;
}
} }
static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr) static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
{ {
intptr_t value = (intptr_t)ptr;
TCGRelocation *r;
tcg_debug_assert(!l->has_value); tcg_debug_assert(!l->has_value);
for (r = l->u.first_reloc; r != NULL; r = r->next) {
bool ok = patch_reloc(r->ptr, r->type, value, r->addend);
tcg_debug_assert(ok);
}
l->has_value = 1; l->has_value = 1;
l->u.value_ptr = ptr; l->u.value_ptr = ptr;
} }
@ -249,15 +230,33 @@ static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
TCGLabel *gen_new_label(TCGContext *s) TCGLabel *gen_new_label(TCGContext *s)
{ {
TCGLabel *l = tcg_malloc(s, sizeof(TCGLabel)); TCGLabel *l = tcg_malloc(s, sizeof(TCGLabel));
TCGLabel ltmp = {0};
ltmp.id = s->nb_labels++; memset(l, 0, sizeof(TCGLabel));
*l = ltmp; l->id = s->nb_labels++;
#ifdef CONFIG_DEBUG_TCG QSIMPLEQ_INIT(&l->relocs);
QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); QSIMPLEQ_INSERT_TAIL(&s->labels, l, next);
#endif
return l; return l;
} }
static bool tcg_resolve_relocs(TCGContext *s)
{
TCGLabel *l;
QSIMPLEQ_FOREACH(l, &s->labels, next) {
TCGRelocation *r;
uintptr_t value = l->u.value;
QSIMPLEQ_FOREACH(r, &l->relocs, next) {
if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
return false;
}
}
}
return true;
}
#include "tcg-target.inc.c" #include "tcg-target.inc.c"
/* pool based memory allocation */ /* pool based memory allocation */
@ -517,9 +516,7 @@ void tcg_func_start(TCGContext *s)
QTAILQ_INIT(&s->ops); QTAILQ_INIT(&s->ops);
QTAILQ_INIT(&s->free_ops); QTAILQ_INIT(&s->free_ops);
#ifdef CONFIG_DEBUG_TCG
QSIMPLEQ_INIT(&s->labels); QSIMPLEQ_INIT(&s->labels);
#endif
} }
static inline TCGTemp *tcg_temp_alloc(TCGContext *s) static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
@ -3386,6 +3383,10 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
} }
#endif #endif
if (!tcg_resolve_relocs(s)) {
return -2;
}
/* flush instruction cache */ /* flush instruction cache */
flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);

View file

@ -244,12 +244,13 @@ typedef uint64_t tcg_insn_unit;
# endif # endif
#endif #endif
typedef struct TCGRelocation { typedef struct TCGRelocation TCGRelocation;
struct TCGRelocation *next; struct TCGRelocation {
int type; QSIMPLEQ_ENTRY(TCGRelocation) next;
tcg_insn_unit *ptr; tcg_insn_unit *ptr;
intptr_t addend; intptr_t addend;
} TCGRelocation; int type;
};
typedef struct TCGLabel TCGLabel; typedef struct TCGLabel TCGLabel;
struct TCGLabel { struct TCGLabel {
@ -260,11 +261,10 @@ struct TCGLabel {
union { union {
uintptr_t value; uintptr_t value;
tcg_insn_unit *value_ptr; tcg_insn_unit *value_ptr;
TCGRelocation *first_reloc;
} u; } u;
#ifdef CONFIG_DEBUG_TCG
QSIMPLEQ_HEAD(, TCGRelocation) relocs;
QSIMPLEQ_ENTRY(TCGLabel) next; QSIMPLEQ_ENTRY(TCGLabel) next;
#endif
}; };
typedef struct TCGPool { typedef struct TCGPool {
@ -784,7 +784,6 @@ struct TCGContext {
#endif #endif
#ifdef CONFIG_DEBUG_TCG #ifdef CONFIG_DEBUG_TCG
QSIMPLEQ_HEAD(, TCGLabel) labels;
int temps_in_use; int temps_in_use;
int goto_tb_issue_mask; int goto_tb_issue_mask;
#endif #endif
@ -821,6 +820,7 @@ struct TCGContext {
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
QTAILQ_HEAD(TCGOpHead, TCGOp) ops, free_ops; QTAILQ_HEAD(TCGOpHead, TCGOp) ops, free_ops;
QSIMPLEQ_HEAD(, TCGLabel) labels;
/* Tells which temporary holds a given register. /* Tells which temporary holds a given register.
It does not take into account fixed registers */ It does not take into account fixed registers */