Commit 7ecd02a0 authored by Richard Henderson's avatar Richard Henderson
Browse files

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: default avatarRichard Henderson <richard.henderson@linaro.org>
parent 6e6c4efe
Loading
Loading
Loading
Loading
+29 −32
Original line number Diff line number Diff line
@@ -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,
                          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->ptr = code_ptr;
    r->addend = addend;
        r->next = l->u.first_reloc;
        l->u.first_reloc = r;
    }
    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;
}
@@ -303,16 +283,32 @@ TCGLabel *gen_new_label(void)
    TCGContext *s = tcg_ctx;
    TCGLabel *l = tcg_malloc(sizeof(TCGLabel));

    *l = (TCGLabel){
        .id = s->nb_labels++
    };
#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;
}

static void set_jmp_reset_offset(TCGContext *s, int which)
{
    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->free_ops);
#ifdef CONFIG_DEBUG_TCG
    QSIMPLEQ_INIT(&s->labels);
#endif
}

static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
@@ -4015,6 +4009,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
        return -1;
    }
#endif
    if (!tcg_resolve_relocs(s)) {
        return -2;
    }

    /* flush instruction cache */
    flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
+7 −8
Original line number Diff line number Diff line
@@ -238,12 +238,13 @@ typedef uint64_t tcg_insn_unit;
    do { if (!(X)) { __builtin_unreachable(); } } while (0)
#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 {
@@ -254,11 +255,9 @@ 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 {
@@ -691,7 +690,6 @@ struct TCGContext {
#endif

#ifdef CONFIG_DEBUG_TCG
    QSIMPLEQ_HEAD(, TCGLabel) labels;
    int temps_in_use;
    int goto_tb_issue_mask;
#endif
@@ -729,6 +727,7 @@ struct TCGContext {
    TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */

    QTAILQ_HEAD(, TCGOp) ops, free_ops;
    QSIMPLEQ_HEAD(, TCGLabel) labels;

    /* Tells which temporary holds a given register.
       It does not take into account fixed registers */