added local temporaries
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 25 May 2008 17:24:00 +0000 (17:24 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 25 May 2008 17:24:00 +0000 (17:24 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4576 c046a42c-6fe2-441c-8c8c-71466251a162

tcg/tcg.c
tcg/tcg.h

index 7e089afb595dfb81e1ba316d19a2b7a332e51f4e..c6b32ecf708ed3f37f3f593bd6aafd4de0689bb5 100644 (file)
--- 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);
index 405968b2d39038b4076228fc5c4f61b95c8684a8..e62969e070ab991b78f5ef90909b5c72ce9ec50f 100644 (file)
--- 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,