* mini-s390x.c, mini-s390x.h: Check for presence of long displacement
[mono.git] / mono / mini / linear-scan.c
index 0e3c37283a7a6da13f9719945c5aea41b03457e4..0e8fca80406e2c3701251a71d1a9dc32c53411f6 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)
@@ -63,7 +64,7 @@ mono_varlist_sort (MonoCompile *cfg, GList *list, int sort_type)
        return NULL;
 }
 
-//#define DEBUG_LSCAN
+// #define DEBUG_LSCAN
 
 void
 mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_mask)
@@ -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,18 +108,18 @@ 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
                        printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, 
                                amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
 #endif
-                       active = g_list_remove_link (active, active);
-                       regs = g_list_prepend (regs, (gpointer)amv->reg);
+                       active = g_list_delete_link (active, active);
+                       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 */
 
@@ -129,7 +130,7 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
                            (!cost_driven && amv->range.last_use.abs_pos > vmv->range.last_use.abs_pos)) {
                                vmv->reg = amv->reg;
                                amv->reg = -1;
-                               active = g_list_remove_link (active, a);
+                               active = g_list_delete_link (active, a);
 
                                if (cost_driven)
                                        active = mono_varlist_insert_sorted (cfg, active, vmv, 2);      
@@ -154,11 +155,11 @@ 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;
 
-                       regs = g_list_remove_link (regs, regs);
+                       regs = g_list_delete_link (regs, regs);
 
 #ifdef DEBUG_LSCAN
                        printf ("ADD    %2d %08x %08x C%d R%d\n",  vmv->idx, 
@@ -188,13 +189,37 @@ 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
+                               //#ifdef MONO_ARCH_HAS_XP_LOCAL_REGALLOC
+                               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);
+                       }
                }
        }
 
@@ -209,6 +234,11 @@ mono_linear_scan (MonoCompile *cfg, GList *vars, GList *regs, regmask_t *used_ma
 
        *used_mask |= used_regs;
 
+#ifdef DEBUG_LSCAN
+       if (cfg->verbose_level > 2)
+               printf ("EXIT: final used mask: %08x\n", *used_mask);
+#endif
+
        g_list_free (regs);
        g_list_free (active);
        g_list_free (vars);