From 45315fd8efb1eeadd4797024beb9b49d0a74e91d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 30 Apr 2019 09:58:44 -0400 Subject: [PATCH] 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 --- qemu/tcg/tcg.c | 63 +++++++++++++++++++++++++------------------------- qemu/tcg/tcg.h | 16 ++++++------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index f9b58959..7e832e4f 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -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, TCGLabel *l, intptr_t addend) { - TCGRelocation *r; + TCGRelocation *r = tcg_malloc(s, 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(s, sizeof(TCGRelocation)); - r->type = type; - r->ptr = code_ptr; - r->addend = addend; - r->next = l->u.first_reloc; - l->u.first_reloc = r; - } + r->type = type; + r->ptr = code_ptr; + r->addend = addend; + QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next); } 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); - 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->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 *l = tcg_malloc(s, sizeof(TCGLabel)); - TCGLabel ltmp = {0}; - ltmp.id = s->nb_labels++; - *l = ltmp; -#ifdef CONFIG_DEBUG_TCG + + memset(l, 0, sizeof(TCGLabel)); + l->id = s->nb_labels++; + QSIMPLEQ_INIT(&l->relocs); + QSIMPLEQ_INSERT_TAIL(&s->labels, l, next); -#endif + 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" /* pool based memory allocation */ @@ -517,9 +516,7 @@ void tcg_func_start(TCGContext *s) QTAILQ_INIT(&s->ops); QTAILQ_INIT(&s->free_ops); -#ifdef CONFIG_DEBUG_TCG QSIMPLEQ_INIT(&s->labels); -#endif } static inline TCGTemp *tcg_temp_alloc(TCGContext *s) @@ -3386,6 +3383,10 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) } #endif + if (!tcg_resolve_relocs(s)) { + return -2; + } + /* flush instruction cache */ flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); diff --git a/qemu/tcg/tcg.h b/qemu/tcg/tcg.h index 60bfa3b6..8ca028d9 100644 --- a/qemu/tcg/tcg.h +++ b/qemu/tcg/tcg.h @@ -244,12 +244,13 @@ typedef uint64_t tcg_insn_unit; # endif #endif -typedef struct TCGRelocation { - struct TCGRelocation *next; - int type; +typedef struct TCGRelocation TCGRelocation; +struct TCGRelocation { + QSIMPLEQ_ENTRY(TCGRelocation) next; tcg_insn_unit *ptr; intptr_t addend; -} TCGRelocation; + int type; +}; typedef struct TCGLabel TCGLabel; struct TCGLabel { @@ -260,11 +261,10 @@ struct TCGLabel { union { uintptr_t value; tcg_insn_unit *value_ptr; - TCGRelocation *first_reloc; } u; -#ifdef CONFIG_DEBUG_TCG + + QSIMPLEQ_HEAD(, TCGRelocation) relocs; QSIMPLEQ_ENTRY(TCGLabel) next; -#endif }; typedef struct TCGPool { @@ -784,7 +784,6 @@ struct TCGContext { #endif #ifdef CONFIG_DEBUG_TCG - QSIMPLEQ_HEAD(, TCGLabel) labels; int temps_in_use; int goto_tb_issue_mask; #endif @@ -821,6 +820,7 @@ struct TCGContext { TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ QTAILQ_HEAD(TCGOpHead, TCGOp) ops, free_ops; + QSIMPLEQ_HEAD(, TCGLabel) labels; /* Tells which temporary holds a given register. It does not take into account fixed registers */