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.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2019-04-21 13:34:35 -07:00
parent 6e6c4efed9
commit 7ecd02a06f
2 changed files with 36 additions and 40 deletions

View File

@ -263,37 +263,17 @@ static __attribute__((unused)) 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(sizeof(TCGRelocation));
if (l->has_value) {
/* FIXME: This may break relocations on RISC targets that
modify instruction fields in place. The caller may not have
written the initial value. */
bool ok = patch_reloc(code_ptr, type, l->u.value, addend);
tcg_debug_assert(ok);
} else {
/* add a new relocation entry */
r = tcg_malloc(sizeof(TCGRelocation));
r->type = type; r->type = type;
r->ptr = code_ptr; r->ptr = code_ptr;
r->addend = addend; r->addend = addend;
r->next = l->u.first_reloc; QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
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;
} }
@ -303,16 +283,32 @@ TCGLabel *gen_new_label(void)
TCGContext *s = tcg_ctx; TCGContext *s = tcg_ctx;
TCGLabel *l = tcg_malloc(sizeof(TCGLabel)); TCGLabel *l = tcg_malloc(sizeof(TCGLabel));
*l = (TCGLabel){ memset(l, 0, sizeof(TCGLabel));
.id = s->nb_labels++ l->id = s->nb_labels++;
}; QSIMPLEQ_INIT(&l->relocs);
#ifdef CONFIG_DEBUG_TCG
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;
}
static void set_jmp_reset_offset(TCGContext *s, int which) static void set_jmp_reset_offset(TCGContext *s, int which)
{ {
size_t off = tcg_current_code_size(s); size_t off = tcg_current_code_size(s);
@ -1096,9 +1092,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)
@ -4015,6 +4009,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
return -1; return -1;
} }
#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

@ -238,12 +238,13 @@ typedef uint64_t tcg_insn_unit;
do { if (!(X)) { __builtin_unreachable(); } } while (0) do { if (!(X)) { __builtin_unreachable(); } } while (0)
#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 {
@ -254,11 +255,9 @@ 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 {
@ -691,7 +690,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
@ -729,6 +727,7 @@ struct TCGContext {
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
QTAILQ_HEAD(, TCGOp) ops, free_ops; QTAILQ_HEAD(, 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 */