2007-10-08 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / linear-scan.c
index f38d02d2e7e30e456b33be6e0f4c77513e91ab2f..cfb4ad327aac3ebc77a0d2e954470d968405223f 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include "mini.h"
+#include <mono/metadata/debug-helpers.h>
 
 GList *
 mono_varlist_insert_sorted (MonoCompile *cfg, GList *list, MonoMethodVar *mv, int sort_type)
@@ -74,7 +75,7 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
        regmask_t used_regs = 0;
        gboolean cost_driven;
 
-       cost_driven = (cfg->comp_done & MONO_COMP_LOOPS);
+       cost_driven = TRUE;
 
 #ifdef DEBUG_LSCAN
        printf ("Linears scan for %s\n", mono_method_full_name (cfg->method, TRUE));
@@ -90,7 +91,7 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
        max_regs = g_list_length (regs);
 
        for (l = regs; l; l = l->next) {
-               int regnum = (int)l->data;
+               int regnum = GPOINTER_TO_INT (l->data);
                g_assert (regnum < G_N_ELEMENTS (gains));
                gains [regnum] = 0;
        }
@@ -107,7 +108,7 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
                while (active) {
                        amv = (MonoMethodVar *)active->data;
 
-                       if (amv->range.last_use.abs_pos >= vmv->range.first_use.abs_pos)
+                       if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
                                break;
 
 #ifdef DEBUG_LSCAN
@@ -115,10 +116,10 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
                                amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
 #endif
                        active = g_list_delete_link (active, active);
-                       regs = g_list_prepend (regs, (gpointer)amv->reg);
+                       regs = g_list_prepend (regs, GINT_TO_POINTER (amv->reg));
                        gains [amv->reg] += amv->spill_costs;
                }
-               
+
                if (active && g_list_length (active) == max_regs) {
                        /* Spill */
 
@@ -154,7 +155,7 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
 
                        g_assert (regs);
 
-                       vmv->reg = (int)regs->data;
+                       vmv->reg = GPOINTER_TO_INT (regs->data);
 
                        used_regs |= 1LL << vmv->reg;
 
@@ -188,13 +189,36 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
                vmv = l->data;
                
                if (vmv->reg >= 0)  {
-                       if (gains [vmv->reg] > mono_arch_regalloc_cost (cfg, vmv)) {
+                       if ((gains [vmv->reg] > mono_arch_regalloc_cost (cfg, vmv)) && (cfg->varinfo [vmv->idx]->opcode != OP_REGVAR)) {
                                cfg->varinfo [vmv->idx]->opcode = OP_REGVAR;
                                cfg->varinfo [vmv->idx]->dreg = vmv->reg;
                                if (cfg->verbose_level > 2)
                                        printf ("REGVAR %d C%d R%d\n", vmv->idx, vmv->spill_costs, vmv->reg);
-                       } else
+                       } else {
+                               if (cfg->verbose_level > 2)
+                                       printf ("COSTLY: %s R%d C%d C%d %s\n", mono_method_full_name (cfg->method, TRUE), vmv->idx, vmv->spill_costs, mono_arch_regalloc_cost (cfg, vmv), mono_arch_regname (vmv->reg));
                                vmv->reg = -1;
+                       }
+               }
+
+               if (vmv->reg == -1) {
+                       if ((vmv->range.first_use.abs_pos >> 16) == (vmv->range.last_use.abs_pos >> 16)) {
+                               /*
+                                * This variables is only used in a single basic block so
+                                * convert it into a virtual register.
+                                * FIXME: This increases register pressure in the local
+                                * allocator, leading to the well known 'branches inside
+                                * basic blocks screw up the allocator' problem.
+                                */
+#if 0
+                               cfg->varinfo [vmv->idx]->opcode = OP_REGVAR;
+                               cfg->varinfo [vmv->idx]->dreg = mono_regstate_next_int (cfg->rs);
+#endif
+                       }
+                       else {
+                               if (cfg->verbose_level > 2)
+                                       printf ("NOT REGVAR: %d\n", vmv->idx);
+                       }
                }
        }