diff mbox

[05/13] tcg: rework liveness analysis

Message ID 1348766113-18373-6-git-send-email-aurelien@aurel32.net
State New
Headers show

Commit Message

Aurelien Jarno Sept. 27, 2012, 5:15 p.m. UTC
Rework the liveness analysis by tracking temps that need to go back to
memory in addition to dead temps tracking. This allows to mark output
arguments as "need sync", and to synchronize them back to memory as soon
as they are not written anymore. This way even arguments mapping to
globals can be marked as "dead", avoiding moves to a new register when
input and outputs are aliased.

In addition it means that registers are freed as soon as temps are not
used anymore, instead of waiting for a basic block end or an op with side
effects. This reduces register spilling especially on CPUs with few
registers, and spread the mov over all the TB, increasing the
performances on in-order CPUs.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 tcg/tcg.c |   64 +++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 37 insertions(+), 27 deletions(-)

Comments

Richard Henderson Sept. 27, 2012, 6:54 p.m. UTC | #1
On 09/27/2012 10:15 AM, Aurelien Jarno wrote:
> Rework the liveness analysis by tracking temps that need to go back to
> memory in addition to dead temps tracking. This allows to mark output
> arguments as "need sync", and to synchronize them back to memory as soon
> as they are not written anymore. This way even arguments mapping to
> globals can be marked as "dead", avoiding moves to a new register when
> input and outputs are aliased.
> 
> In addition it means that registers are freed as soon as temps are not
> used anymore, instead of waiting for a basic block end or an op with side
> effects. This reduces register spilling especially on CPUs with few
> registers, and spread the mov over all the TB, increasing the
> performances on in-order CPUs.
> 
> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> ---
>  tcg/tcg.c |   64 +++++++++++++++++++++++++++++++++++--------------------------
>  1 file changed, 37 insertions(+), 27 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~
diff mbox

Patch

diff --git a/tcg/tcg.c b/tcg/tcg.c
index b89ab04..49e2478 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1183,31 +1183,27 @@  static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
     }
 }
 
-/* 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)
+/* liveness analysis: end of function: all temps are dead, and globals
+   should be in memory. */
+static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps,
+                                   uint8_t *mem_temps)
 {
-    memset(dead_temps, 0, s->nb_globals);
-    memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
+    memset(dead_temps, 1, s->nb_temps);
+    memset(mem_temps, 1, s->nb_globals);
+    memset(mem_temps + s->nb_globals, 0, 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)
+/* liveness analysis: end of basic block: all temps are dead, globals
+   and local temps should be in memory. */
+static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps,
+                                 uint8_t *mem_temps)
 {
     int i;
-    TCGTemp *ts;
 
-    memset(dead_temps, 0, s->nb_globals);
-    ts = &s->temps[s->nb_globals];
+    memset(dead_temps, 1, s->nb_temps);
+    memset(mem_temps, 1, 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++;
+        mem_temps[i] = s->temps[i].temp_local;
     }
 }
 
@@ -1220,7 +1216,7 @@  static void tcg_liveness_analysis(TCGContext *s)
     TCGOpcode op;
     TCGArg *args;
     const TCGOpDef *def;
-    uint8_t *dead_temps;
+    uint8_t *dead_temps, *mem_temps;
     uint16_t dead_args;
     uint8_t sync_args;
     
@@ -1232,7 +1228,8 @@  static void tcg_liveness_analysis(TCGContext *s)
     s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t));
     
     dead_temps = tcg_malloc(s->nb_temps);
-    memset(dead_temps, 1, s->nb_temps);
+    mem_temps = tcg_malloc(s->nb_temps);
+    tcg_la_func_end(s, dead_temps, mem_temps);
 
     args = gen_opparam_ptr;
     op_index = nb_ops - 1;
@@ -1256,8 +1253,9 @@  static void tcg_liveness_analysis(TCGContext *s)
                 if (call_flags & TCG_CALL_PURE) {
                     for(i = 0; i < nb_oargs; i++) {
                         arg = args[i];
-                        if (!dead_temps[arg])
+                        if (!dead_temps[arg] || mem_temps[arg]) {
                             goto do_not_remove_call;
+                        }
                     }
                     tcg_set_nop(s, gen_opc_buf + op_index, 
                                 args - 1, nb_args);
@@ -1272,12 +1270,17 @@  static void tcg_liveness_analysis(TCGContext *s)
                         if (dead_temps[arg]) {
                             dead_args |= (1 << i);
                         }
+                        if (mem_temps[arg]) {
+                            sync_args |= (1 << i);
+                        }
                         dead_temps[arg] = 1;
+                        mem_temps[arg] = 0;
                     }
                     
                     if (!(call_flags & TCG_CALL_CONST)) {
-                        /* globals are live (they may be used by the call) */
-                        memset(dead_temps, 0, s->nb_globals);
+                        /* globals should go back to memory */
+                        memset(dead_temps, 1, s->nb_globals);
+                        memset(mem_temps, 1, s->nb_globals);
                     }
 
                     /* input args are live */
@@ -1307,6 +1310,7 @@  static void tcg_liveness_analysis(TCGContext *s)
             args--;
             /* mark the temporary as dead */
             dead_temps[args[0]] = 1;
+            mem_temps[args[0]] = 0;
             break;
         case INDEX_op_end:
             break;
@@ -1322,8 +1326,9 @@  static void tcg_liveness_analysis(TCGContext *s)
             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
                 for(i = 0; i < nb_oargs; i++) {
                     arg = args[i];
-                    if (!dead_temps[arg])
+                    if (!dead_temps[arg] || mem_temps[arg]) {
                         goto do_not_remove;
+                    }
                 }
                 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
 #ifdef CONFIG_PROFILER
@@ -1340,15 +1345,20 @@  static void tcg_liveness_analysis(TCGContext *s)
                     if (dead_temps[arg]) {
                         dead_args |= (1 << i);
                     }
+                    if (mem_temps[arg]) {
+                        sync_args |= (1 << i);
+                    }
                     dead_temps[arg] = 1;
+                    mem_temps[arg] = 0;
                 }
 
                 /* if end of basic block, update */
                 if (def->flags & TCG_OPF_BB_END) {
-                    tcg_la_bb_end(s, dead_temps);
+                    tcg_la_bb_end(s, dead_temps, mem_temps);
                 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
-                    /* globals are live */
-                    memset(dead_temps, 0, s->nb_globals);
+                    /* globals should go back to memory */
+                    memset(dead_temps, 1, s->nb_globals);
+                    memset(mem_temps, 1, s->nb_globals);
                 }
 
                 /* input args are live */