tcg: Dynamically allocate TCGOps

With no fixed array allocation, we can't overflow a buffer.
This will be important as optimizations related to host vectors
may expand the number of ops used.

Use QTAILQ to link the ops together.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2017-11-02 15:19:14 +01:00
parent f764718d0c
commit 15fa08f845
12 changed files with 78 additions and 158 deletions

125
tcg/tcg.c
View file

@ -862,9 +862,8 @@ void tcg_func_start(TCGContext *s)
s->goto_tb_issue_mask = 0;
#endif
s->gen_op_buf[0].next = 1;
s->gen_op_buf[0].prev = 0;
s->gen_next_op_idx = 1;
QTAILQ_INIT(&s->ops);
QTAILQ_INIT(&s->free_ops);
}
static inline TCGTemp *tcg_temp_alloc(TCGContext *s)
@ -1339,7 +1338,6 @@ bool tcg_op_supported(TCGOpcode op)
and endian swap in tcg_reg_alloc_call(). */
void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
{
TCGContext *s = tcg_ctx;
int i, real_args, nb_rets, pi;
unsigned sizemask, flags;
TCGHelperInfo *info;
@ -1395,17 +1393,7 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
}
#endif /* TCG_TARGET_EXTEND_ARGS */
i = s->gen_next_op_idx;
tcg_debug_assert(i < OPC_BUF_SIZE);
s->gen_op_buf[0].prev = i;
s->gen_next_op_idx = i + 1;
op = &s->gen_op_buf[i];
/* Set links for sequential allocation during translation. */
memset(op, 0, offsetof(TCGOp, args));
op->opc = INDEX_op_call;
op->prev = i - 1;
op->next = i + 1;
op = tcg_emit_op(INDEX_op_call);
pi = 0;
if (ret != NULL) {
@ -1622,20 +1610,18 @@ void tcg_dump_ops(TCGContext *s)
{
char buf[128];
TCGOp *op;
int oi;
for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) {
QTAILQ_FOREACH(op, &s->ops, link) {
int i, k, nb_oargs, nb_iargs, nb_cargs;
const TCGOpDef *def;
TCGOpcode c;
int col = 0;
op = &s->gen_op_buf[oi];
c = op->opc;
def = &tcg_op_defs[c];
if (c == INDEX_op_insn_start) {
col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : "");
col += qemu_log("\n ----");
for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
target_ulong a;
@ -1898,65 +1884,51 @@ static void process_op_defs(TCGContext *s)
void tcg_op_remove(TCGContext *s, TCGOp *op)
{
int next = op->next;
int prev = op->prev;
/* We should never attempt to remove the list terminator. */
tcg_debug_assert(op != &s->gen_op_buf[0]);
s->gen_op_buf[next].prev = prev;
s->gen_op_buf[prev].next = next;
memset(op, 0, sizeof(*op));
QTAILQ_REMOVE(&s->ops, op, link);
QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
#ifdef CONFIG_PROFILER
atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
#endif
}
static TCGOp *tcg_op_alloc(TCGOpcode opc)
{
TCGContext *s = tcg_ctx;
TCGOp *op;
if (likely(QTAILQ_EMPTY(&s->free_ops))) {
op = tcg_malloc(sizeof(TCGOp));
} else {
op = QTAILQ_FIRST(&s->free_ops);
QTAILQ_REMOVE(&s->free_ops, op, link);
}
memset(op, 0, offsetof(TCGOp, link));
op->opc = opc;
return op;
}
TCGOp *tcg_emit_op(TCGOpcode opc)
{
TCGOp *op = tcg_op_alloc(opc);
QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
return op;
}
TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
TCGOpcode opc, int nargs)
{
int oi = s->gen_next_op_idx;
int prev = old_op->prev;
int next = old_op - s->gen_op_buf;
TCGOp *new_op;
tcg_debug_assert(oi < OPC_BUF_SIZE);
s->gen_next_op_idx = oi + 1;
new_op = &s->gen_op_buf[oi];
*new_op = (TCGOp){
.opc = opc,
.prev = prev,
.next = next
};
s->gen_op_buf[prev].next = oi;
old_op->prev = oi;
TCGOp *new_op = tcg_op_alloc(opc);
QTAILQ_INSERT_BEFORE(old_op, new_op, link);
return new_op;
}
TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
TCGOpcode opc, int nargs)
{
int oi = s->gen_next_op_idx;
int prev = old_op - s->gen_op_buf;
int next = old_op->next;
TCGOp *new_op;
tcg_debug_assert(oi < OPC_BUF_SIZE);
s->gen_next_op_idx = oi + 1;
new_op = &s->gen_op_buf[oi];
*new_op = (TCGOp){
.opc = opc,
.prev = prev,
.next = next
};
s->gen_op_buf[next].prev = oi;
old_op->next = oi;
TCGOp *new_op = tcg_op_alloc(opc);
QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
return new_op;
}
@ -2006,23 +1978,19 @@ static void tcg_la_bb_end(TCGContext *s)
static void liveness_pass_1(TCGContext *s)
{
int nb_globals = s->nb_globals;
int oi, oi_prev;
TCGOp *op, *op_prev;
tcg_la_func_end(s);
for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) {
QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, TCGOpHead, link, op_prev) {
int i, nb_iargs, nb_oargs;
TCGOpcode opc_new, opc_new2;
bool have_opc_new2;
TCGLifeData arg_life = 0;
TCGTemp *arg_ts;
TCGOp * const op = &s->gen_op_buf[oi];
TCGOpcode opc = op->opc;
const TCGOpDef *def = &tcg_op_defs[opc];
oi_prev = op->prev;
switch (opc) {
case INDEX_op_call:
{
@ -2233,8 +2201,9 @@ static void liveness_pass_1(TCGContext *s)
static bool liveness_pass_2(TCGContext *s)
{
int nb_globals = s->nb_globals;
int nb_temps, i, oi, oi_next;
int nb_temps, i;
bool changes = false;
TCGOp *op, *op_next;
/* Create a temporary for each indirect global. */
for (i = 0; i < nb_globals; ++i) {
@ -2256,16 +2225,13 @@ static bool liveness_pass_2(TCGContext *s)
its->state = TS_DEAD;
}
for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
TCGOp *op = &s->gen_op_buf[oi];
QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
TCGOpcode opc = op->opc;
const TCGOpDef *def = &tcg_op_defs[opc];
TCGLifeData arg_life = op->life;
int nb_iargs, nb_oargs, call_flags;
TCGTemp *arg_ts, *dir_ts;
oi_next = op->next;
if (opc == INDEX_op_call) {
nb_oargs = op->callo;
nb_iargs = op->calli;
@ -3168,13 +3134,16 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
#ifdef CONFIG_PROFILER
TCGProfile *prof = &s->prof;
#endif
int i, oi, oi_next, num_insns;
int i, num_insns;
TCGOp *op;
#ifdef CONFIG_PROFILER
{
int n;
n = s->gen_op_buf[0].prev + 1;
QTAILQ_FOREACH(op, &s->ops, link) {
n++;
}
atomic_set(&prof->op_count, prof->op_count + n);
if (n > prof->op_count_max) {
atomic_set(&prof->op_count_max, n);
@ -3260,11 +3229,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
#endif
num_insns = -1;
for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) {
TCGOp * const op = &s->gen_op_buf[oi];
QTAILQ_FOREACH(op, &s->ops, link) {
TCGOpcode opc = op->opc;
oi_next = op->next;
#ifdef CONFIG_PROFILER
atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
#endif