added local temporaries

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4576 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2008-05-25 17:24:00 +00:00
parent 98fc56145e
commit 641d5fbe6b
2 changed files with 103 additions and 45 deletions

126
tcg/tcg.c
View File

@ -269,7 +269,7 @@ void tcg_func_start(TCGContext *s)
int i;
tcg_pool_reset(s);
s->nb_temps = s->nb_globals;
for(i = 0; i < TCG_TYPE_COUNT; i++)
for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
s->first_free_temp[i] = -1;
s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
s->nb_labels = 0;
@ -407,19 +407,23 @@ TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
return MAKE_TCGV(idx);
}
TCGv tcg_temp_new(TCGType type)
TCGv tcg_temp_new_internal(TCGType type, int temp_local)
{
TCGContext *s = &tcg_ctx;
TCGTemp *ts;
int idx;
int idx, k;
idx = s->first_free_temp[type];
k = type;
if (temp_local)
k += TCG_TYPE_COUNT;
idx = s->first_free_temp[k];
if (idx != -1) {
/* There is already an available temp with the
right type */
ts = &s->temps[idx];
s->first_free_temp[type] = ts->next_free_temp;
s->first_free_temp[k] = ts->next_free_temp;
ts->temp_allocated = 1;
assert(ts->temp_local == temp_local);
} else {
idx = s->nb_temps;
#if TCG_TARGET_REG_BITS == 32
@ -429,11 +433,13 @@ TCGv tcg_temp_new(TCGType type)
ts->base_type = type;
ts->type = TCG_TYPE_I32;
ts->temp_allocated = 1;
ts->temp_local = temp_local;
ts->name = NULL;
ts++;
ts->base_type = TCG_TYPE_I32;
ts->type = TCG_TYPE_I32;
ts->temp_allocated = 1;
ts->temp_local = temp_local;
ts->name = NULL;
s->nb_temps += 2;
} else
@ -444,6 +450,7 @@ TCGv tcg_temp_new(TCGType type)
ts->base_type = type;
ts->type = type;
ts->temp_allocated = 1;
ts->temp_local = temp_local;
ts->name = NULL;
s->nb_temps++;
}
@ -456,15 +463,17 @@ void tcg_temp_free(TCGv arg)
TCGContext *s = &tcg_ctx;
TCGTemp *ts;
int idx = GET_TCGV(arg);
TCGType type;
int k;
assert(idx >= s->nb_globals && idx < s->nb_temps);
ts = &s->temps[idx];
assert(ts->temp_allocated != 0);
ts->temp_allocated = 0;
type = ts->base_type;
ts->next_free_temp = s->first_free_temp[type];
s->first_free_temp[type] = idx;
k = ts->base_type;
if (ts->temp_local)
k += TCG_TYPE_COUNT;
ts->next_free_temp = s->first_free_temp[k];
s->first_free_temp[k] = idx;
}
@ -683,7 +692,10 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
if (idx < s->nb_globals) {
pstrcpy(buf, buf_size, ts->name);
} else {
snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
if (ts->temp_local)
snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
else
snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
}
return buf;
}
@ -987,13 +999,34 @@ static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
}
}
/* liveness analysis: end of basic block: globals are live, temps are dead */
static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
/* liveness analysis: end of function: globals are live, temps are
dead. */
/* XXX: at this stage, not used as there would be little gains because
most TBs end with a conditional jump. */
static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
{
memset(dead_temps, 0, s->nb_globals);
memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
}
/* liveness analysis: end of basic block: globals are live, temps are
dead, local temps are live. */
static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
{
int i;
TCGTemp *ts;
memset(dead_temps, 0, s->nb_globals);
ts = &s->temps[s->nb_globals];
for(i = s->nb_globals; i < s->nb_temps; i++) {
if (ts->temp_local)
dead_temps[i] = 0;
else
dead_temps[i] = 1;
ts++;
}
}
/* Liveness analysis : update the opc_dead_iargs array to tell if a
given input arguments is dead. Instructions updating dead
temporaries are removed. */
@ -1366,37 +1399,48 @@ static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
tcg_abort();
}
/* save a temporary to memory. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
{
TCGTemp *ts;
int reg;
ts = &s->temps[temp];
if (!ts->fixed_reg) {
switch(ts->val_type) {
case TEMP_VAL_REG:
tcg_reg_free(s, ts->reg);
break;
case TEMP_VAL_DEAD:
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_CONST:
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
allocated_regs);
if (!ts->mem_allocated)
temp_allocate_frame(s, temp);
tcg_out_movi(s, ts->type, reg, ts->val);
tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_MEM:
break;
default:
tcg_abort();
}
}
}
/* save globals to their cannonical location and assume they can be
modified be the following code. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
{
TCGTemp *ts;
int i, reg;
int i;
for(i = 0; i < s->nb_globals; i++) {
ts = &s->temps[i];
if (!ts->fixed_reg) {
switch(ts->val_type) {
case TEMP_VAL_REG:
tcg_reg_free(s, ts->reg);
break;
case TEMP_VAL_DEAD:
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_CONST:
reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
allocated_regs);
tcg_out_movi(s, ts->type, reg, ts->val);
tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
ts->val_type = TEMP_VAL_MEM;
break;
case TEMP_VAL_MEM:
break;
default:
tcg_abort();
}
}
temp_save(s, i, allocated_regs);
}
}
@ -1409,10 +1453,14 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
for(i = s->nb_globals; i < s->nb_temps; i++) {
ts = &s->temps[i];
if (ts->val_type == TEMP_VAL_REG) {
s->reg_to_temp[ts->reg] = -1;
if (ts->temp_local) {
temp_save(s, i, allocated_regs);
} else {
if (ts->val_type == TEMP_VAL_REG) {
s->reg_to_temp[ts->reg] = -1;
}
ts->val_type = TEMP_VAL_DEAD;
}
ts->val_type = TEMP_VAL_DEAD;
}
save_globals(s, allocated_regs);

View File

@ -189,6 +189,9 @@ typedef struct TCGTemp {
unsigned int fixed_reg:1;
unsigned int mem_coherent:1;
unsigned int mem_allocated:1;
unsigned int temp_local:1; /* If true, the temp is saved accross
basic blocks. Otherwise, it is not
preserved accross basic blocks. */
unsigned int temp_allocated:1; /* never used for code gen */
/* index of next free temp of same base type, -1 if end */
int next_free_temp;
@ -212,11 +215,8 @@ struct TCGContext {
TCGTemp *temps; /* globals first, temps after */
int nb_globals;
int nb_temps;
int first_free_temp[TCG_TYPE_COUNT]; /* index of free temps, -1 if none */
/* constant indexes (end of temp array) */
int const_start;
int const_end;
/* index of free temps, -1 if none */
int first_free_temp[TCG_TYPE_COUNT * 2];
/* goto_tb support */
uint8_t *code_buf;
@ -224,8 +224,10 @@ struct TCGContext {
uint16_t *tb_next_offset;
uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
/* liveness analysis */
uint16_t *op_dead_iargs; /* for each operation, each bit tells if the
corresponding input argument is dead */
/* tells in which temporary a given register is. It does not take
into account fixed registers */
int reg_to_temp[TCG_TARGET_NB_REGS];
@ -305,7 +307,15 @@ TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2,
const char *name);
TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
const char *name);
TCGv tcg_temp_new(TCGType type);
TCGv tcg_temp_new_internal(TCGType type, int temp_local);
static inline TCGv tcg_temp_new(TCGType type)
{
return tcg_temp_new_internal(type, 0);
}
static inline TCGv tcg_temp_local_new(TCGType type)
{
return tcg_temp_new_internal(type, 1);
}
void tcg_temp_free(TCGv arg);
char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg);
void tcg_dump_info(FILE *f,