diff --git a/tcg/tcg.c b/tcg/tcg.c index 7e089afb59..c6b32ecf70 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -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); diff --git a/tcg/tcg.h b/tcg/tcg.h index 405968b2d3..e62969e070 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -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,