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;
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
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
ts->base_type = type;
ts->type = type;
ts->temp_allocated = 1;
+ ts->temp_local = temp_local;
ts->name = NULL;
s->nb_temps++;
}
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;
}
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;
}
}
}
-/* 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. */
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);
}
}
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);
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;
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;
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];
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,