* Exception.cs: Cosmetic change to default exception message on
[mono.git] / mono / mini / mini-codegen.c
index 57c1c9bbccbb78a9b05974fbc0702e141d99216d..d4b1acb282129d0a6736c2cf160d801cb555cab7 100644 (file)
@@ -6,7 +6,9 @@
 
 #include <string.h>
 #include <math.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 
 #define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 2, a;)
 
-#if defined(__x86_64__)
-const char * const amd64_desc [OP_LAST];
-static const char*const * ins_spec = amd64_desc;
-#elif defined(__sparc__) || defined(sparc)
-const char * const sparc_desc [OP_LAST];
-static const char*const * ins_spec = sparc_desc;
-#elif defined(__mips__) || defined(mips)
-const char * const mips_desc [OP_LAST];
-static const char*const * ins_spec = mips_desc;
-#elif defined(__i386__)
-extern const char * const x86_desc [OP_LAST];
-static const char*const * ins_spec = x86_desc;
-#elif defined(__ia64__)
-const char * const ia64_desc [OP_LAST];
-static const char*const * ins_spec = ia64_desc;
-#elif defined(__arm__)
-const char * const arm_cpu_desc [OP_LAST];
-static const char*const * ins_spec = arm_cpu_desc;
-#elif defined(__s390x__)
-const char * const s390x_cpu_desc [OP_LAST];
-static const char*const * ins_spec = s390x_cpu_desc;
-#elif defined(__s390__)
-const char * const s390_cpu_desc [OP_LAST];
-static const char*const * ins_spec = s390_cpu_desc;
-#elif defined(__alpha__)
-const char * const alpha_desc [OP_LAST];
-static const char*const * ins_spec = alpha_desc;
-#elif defined(__ppc__) || defined(__powerpc__)
-extern const char * const ppcg4 [OP_LAST];
-static const char*const * ins_spec = ppcg4;
-#else
-#error "Not implemented"
-#endif
-
 #define use_fpstack MONO_ARCH_USE_FPSTACK
 
 static inline GSList*
@@ -85,8 +53,7 @@ g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
 
 static inline void
 mono_regstate2_reset (MonoRegState *rs) {
-       rs->next_vireg = MONO_MAX_IREGS;
-       rs->next_vfreg = MONO_MAX_FREGS;
+       rs->next_vreg = MONO_MAX_IREGS;
 }
 
 static inline MonoRegState*
@@ -101,54 +68,57 @@ mono_regstate2_new (void)
 
 static inline void
 mono_regstate2_free (MonoRegState *rs) {
-       g_free (rs->iassign);
-       if (rs->iassign != rs->fassign)
-               g_free (rs->fassign);
+       g_free (rs->vassign);
        g_free (rs);
 }
 
 static inline void
-mono_regstate2_assign (MonoRegState *rs) {
-       rs->max_ireg = -1;
-
-       if (rs->next_vireg > rs->iassign_size) {
-               g_free (rs->iassign);
-               rs->iassign_size = MAX (rs->next_vireg, 256);
-               rs->iassign = g_malloc (rs->iassign_size * sizeof (int));
+mono_regstate_assign (MonoRegState *rs) {
+       if (rs->next_vreg > rs->vassign_size) {
+               g_free (rs->vassign);
+               rs->vassign_size = MAX (rs->next_vreg, 256);
+               rs->vassign = g_malloc (rs->vassign_size * sizeof (int));
        }
 
        memset (rs->isymbolic, 0, MONO_MAX_IREGS * sizeof (rs->isymbolic [0]));
-       memset (rs->iassign, -1, sizeof (rs->iassign [0]) * rs->next_vireg);
+       memset (rs->vassign, -1, sizeof (rs->vassign [0]) * rs->next_vreg);
 
-       if (rs->next_vfreg > rs->fassign_size) {
-               g_free (rs->fassign);
-               rs->fassign = g_malloc (MAX (MONO_MAX_FREGS, rs->next_vfreg) * sizeof (int));
-               rs->fassign_size = rs->next_vfreg;
-       }
-
-       if (rs->next_vfreg > MONO_MAX_FREGS) {
-               memset (rs->fsymbolic, 0, MONO_MAX_IREGS * sizeof (rs->fsymbolic [0]));
-               memset (rs->fassign, -1, sizeof (rs->fassign [0]) * rs->next_vfreg);
-       }
+       memset (rs->fsymbolic, 0, MONO_MAX_FREGS * sizeof (rs->fsymbolic [0]));
 }
 
 static inline int
-mono_regstate2_alloc_int (MonoRegState *rs, regmask_t allow)
+mono_regstate_alloc_int (MonoRegState *rs, regmask_t allow)
 {
-       int i;
        regmask_t mask = allow & rs->ifree_mask;
+
+#if defined(__x86_64__) && defined(__GNUC__)
+ {
+       guint64 i;
+
+       if (mask == 0)
+               return -1;
+
+       __asm__("bsfq %1,%0\n\t"
+                       : "=r" (i) : "rm" (mask));
+
+       rs->ifree_mask &= ~ ((regmask_t)1 << i);
+       return i;
+ }
+#else
+       int i;
+
        for (i = 0; i < MONO_MAX_IREGS; ++i) {
                if (mask & ((regmask_t)1 << i)) {
                        rs->ifree_mask &= ~ ((regmask_t)1 << i);
-                       rs->max_ireg = MAX (rs->max_ireg, i);
                        return i;
                }
        }
        return -1;
+#endif
 }
 
 static inline void
-mono_regstate2_free_int (MonoRegState *rs, int reg)
+mono_regstate_free_int (MonoRegState *rs, int reg)
 {
        if (reg >= 0) {
                rs->ifree_mask |= (regmask_t)1 << reg;
@@ -157,7 +127,7 @@ mono_regstate2_free_int (MonoRegState *rs, int reg)
 }
 
 static inline int
-mono_regstate2_alloc_float (MonoRegState *rs, regmask_t allow)
+mono_regstate_alloc_float (MonoRegState *rs, regmask_t allow)
 {
        int i;
        regmask_t mask = allow & rs->ffree_mask;
@@ -171,7 +141,7 @@ mono_regstate2_alloc_float (MonoRegState *rs, regmask_t allow)
 }
 
 static inline void
-mono_regstate2_free_float (MonoRegState *rs, int reg)
+mono_regstate_free_float (MonoRegState *rs, int reg)
 {
        if (reg >= 0) {
                rs->ffree_mask |= (regmask_t)1 << reg;
@@ -182,9 +152,9 @@ mono_regstate2_free_float (MonoRegState *rs, int reg)
 static inline int
 mono_regstate2_next_long (MonoRegState *rs)
 {
-       int rval = rs->next_vireg;
+       int rval = rs->next_vreg;
 
-       rs->next_vireg += 2;
+       rs->next_vreg += 2;
 
        return rval;
 }
@@ -246,7 +216,7 @@ resize_spill_info (MonoCompile *cfg, gboolean fp)
  * spill variable if necessary. 
  */
 static inline int
-mono_spillvar_offset (MonoCompile *cfg, int spillvar)
+mono_spillvar_offset_int (MonoCompile *cfg, int spillvar)
 {
        MonoSpillInfo *info;
 
@@ -275,8 +245,6 @@ mono_spillvar_offset (MonoCompile *cfg, int spillvar)
        return info->offset;
 }
 
-#if MONO_ARCH_USE_FPSTACK
-
 /*
  * returns the offset used by spillvar. It allocates a new
  * spill float variable if necessary. 
@@ -312,6 +280,17 @@ mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
        return info->offset;
 }
 
+static inline int
+mono_spillvar_offset (MonoCompile *cfg, int spillvar, gboolean fp)
+{
+       if (fp)
+               return mono_spillvar_offset_float (cfg, spillvar);
+       else
+               return mono_spillvar_offset_int (cfg, spillvar);
+}
+
+#if MONO_ARCH_USE_FPSTACK
+
 /*
  * Creates a store for spilled floating point items
  */
@@ -360,7 +339,7 @@ create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
-#define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
+#define rassign(cfg,reg,fp) ((cfg)->rs->vassign [(reg)])
 
 #ifdef MONO_ARCH_INST_IS_FLOAT
 #define dreg_is_fp(spec)  (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
@@ -372,9 +351,9 @@ create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
 #define dreg_is_fp(spec)  (spec [MONO_INST_DEST] == 'f')
 #endif
 
-#define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_spec [(ins)->opcode]))
-#define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_spec [(ins)->opcode]))
-#define dreg_is_fp_ins(ins)  (dreg_is_fp (ins_spec [(ins)->opcode]))
+#define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_get_spec ((ins)->opcode)))
+#define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_get_spec ((ins)->opcode)))
+#define dreg_is_fp_ins(ins)  (dreg_is_fp (ins_get_spec ((ins)->opcode)))
 
 #define regpair_reg2_mask(desc,hreg1) ((MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1) != -1) ? (regmask (MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1))) : MONO_ARCH_CALLEE_REGS)
 
@@ -399,7 +378,7 @@ typedef struct {
 void
 mono_print_ins (int i, MonoInst *ins)
 {
-       const char *spec = ins_spec [ins->opcode];
+       const char *spec = ins_get_spec (ins->opcode);
        printf ("\t%-2d %s", i, mono_inst_name (ins->opcode));
        if (!spec)
                g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
@@ -475,7 +454,7 @@ struct InstList {
 static inline InstList*
 inst_list_prepend (guint8 *mem, InstList *list, MonoInst *data)
 {
-       InstList *item = (InstList*)mem;
+       InstList *item = (InstList*)(gpointer)mem;
        item->data = data;
        item->prev = NULL;
        item->next = list;
@@ -534,25 +513,22 @@ get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, in
        int i, sel, spill;
        int *assign, *symbolic;
 
-       if (fp) {
-               assign = cfg->rs->fassign;
+       assign = cfg->rs->vassign;
+       if (fp)
                symbolic = cfg->rs->fsymbolic;
-       }
-       else {
-               assign = cfg->rs->iassign;
+       else
                symbolic = cfg->rs->isymbolic;
-       }       
        
-       sel = assign [reg];
+       sel = cfg->rs->vassign [reg];
        /*i = cfg->rs->isymbolic [sel];
        g_assert (i == reg);*/
        i = reg;
        spill = ++cfg->spill_count;
        assign [i] = -spill - 1;
        if (fp)
-               mono_regstate2_free_float (cfg->rs, sel);
+               mono_regstate_free_float (cfg->rs, sel);
        else
-               mono_regstate2_free_int (cfg->rs, sel);
+               mono_regstate_free_int (cfg->rs, sel);
        /* we need to create a spill var and insert a load to sel after the current instruction */
        if (fp)
                MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
@@ -560,13 +536,13 @@ get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, in
                MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
        load->dreg = sel;
        load->inst_basereg = cfg->frame_reg;
-       load->inst_offset = mono_spillvar_offset (cfg, spill);
+       load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
        insert_after_ins (ins, item, load);
        DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
        if (fp)
-               i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
+               i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
        else
-               i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
+               i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
        g_assert (i == sel);
 
        return sel;
@@ -584,14 +560,11 @@ get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_
        int i, sel, spill;
        int *assign, *symbolic;
 
-       if (fp) {
-               assign = cfg->rs->fassign;
+       assign = cfg->rs->vassign;
+       if (fp)
                symbolic = cfg->rs->fsymbolic;
-       }
-       else {
-               assign = cfg->rs->iassign;
+       else
                symbolic = cfg->rs->isymbolic;
-       }
 
        DEBUG (printf ("\tstart regmask to assign R%d: 0x%08" G_GUINT64_FORMAT " (R%d <- R%d R%d)\n", reg, (guint64)regmask, ins->dreg, ins->sreg1, ins->sreg2));
        /* exclude the registers in the current instruction */
@@ -629,8 +602,8 @@ get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_
 
                i = cfg->rs->fsymbolic [sel];
                spill = ++cfg->spill_count;
-               cfg->rs->fassign [i] = -spill - 1;
-               mono_regstate2_free_float (cfg->rs, sel);
+               cfg->rs->vassign [i] = -spill - 1;
+               mono_regstate_free_float (cfg->rs, sel);
        }
        else {
                for (i = 0; i < MONO_MAX_IREGS; ++i) {
@@ -643,21 +616,21 @@ get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, regmask_
 
                i = cfg->rs->isymbolic [sel];
                spill = ++cfg->spill_count;
-               cfg->rs->iassign [i] = -spill - 1;
-               mono_regstate2_free_int (cfg->rs, sel);
+               cfg->rs->vassign [i] = -spill - 1;
+               mono_regstate_free_int (cfg->rs, sel);
        }
 
        /* we need to create a spill var and insert a load to sel after the current instruction */
        MONO_INST_NEW (cfg, load, fp ? OP_LOADR8_MEMBASE : OP_LOAD_MEMBASE);
        load->dreg = sel;
        load->inst_basereg = cfg->frame_reg;
-       load->inst_offset = mono_spillvar_offset (cfg, spill);
+       load->inst_offset = mono_spillvar_offset (cfg, spill, fp);
        insert_after_ins (ins, item, load);
        DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill, (long)load->inst_offset, i, mono_regname_full (sel, fp)));
        if (fp)
-               i = mono_regstate2_alloc_float (cfg->rs, regmask (sel));
+               i = mono_regstate_alloc_float (cfg->rs, regmask (sel));
        else
-               i = mono_regstate2_alloc_int (cfg->rs, regmask (sel));
+               i = mono_regstate_alloc_int (cfg->rs, regmask (sel));
        g_assert (i == sel);
        
        return sel;
@@ -669,7 +642,7 @@ free_up_ireg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg)
        if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
                DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
                get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], FALSE);
-               mono_regstate2_free_int (cfg->rs, hreg);
+               mono_regstate_free_int (cfg->rs, hreg);
        }
 }
 
@@ -680,14 +653,14 @@ free_up_reg (MonoCompile *cfg, InstList *item, MonoInst *ins, int hreg, gboolean
                if (!(cfg->rs->ffree_mask & (regmask (hreg)))) {
                        DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
                        get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
-                       mono_regstate2_free_float (cfg->rs, hreg);
+                       mono_regstate_free_float (cfg->rs, hreg);
                }
        }
        else {
                if (!(cfg->rs->ifree_mask & (regmask (hreg)))) {
                        DEBUG (printf ("\tforced spill of R%d\n", cfg->rs->isymbolic [hreg]));
                        get_register_force_spilling (cfg, item, ins, cfg->rs->isymbolic [hreg], fp);
-                       mono_regstate2_free_int (cfg->rs, hreg);
+                       mono_regstate_free_int (cfg->rs, hreg);
                }
        }
 }
@@ -721,7 +694,7 @@ create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoIn
        MONO_INST_NEW (cfg, store, fp ? OP_STORER8_MEMBASE_REG : OP_STORE_MEMBASE_REG);
        store->sreg1 = reg;
        store->inst_destbasereg = cfg->frame_reg;
-       store->inst_offset = mono_spillvar_offset (cfg, spill);
+       store->inst_offset = mono_spillvar_offset (cfg, spill, fp);
        if (ins) {
                store->next = ins->next;
                ins->next = store;
@@ -743,14 +716,14 @@ alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_ma
        int val;
 
        if (info && info->preferred_mask) {
-               val = mono_regstate2_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
+               val = mono_regstate_alloc_int (cfg->rs, info->preferred_mask & dest_mask);
                if (val >= 0) {
                        DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg, mono_arch_regname (val)));
                        return val;
                }
        }
 
-       val = mono_regstate2_alloc_int (cfg->rs, dest_mask);
+       val = mono_regstate_alloc_int (cfg->rs, dest_mask);
        if (val < 0)
                val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, FALSE);
 
@@ -762,7 +735,7 @@ alloc_float_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, regmask_t dest_
 {
        int val;
 
-       val = mono_regstate2_alloc_float (cfg->rs, dest_mask);
+       val = mono_regstate_alloc_float (cfg->rs, dest_mask);
 
        if (val < 0) {
                val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg, TRUE);
@@ -788,16 +761,19 @@ assign_reg (MonoCompile *cfg, MonoRegState *rs, int reg, int hreg, gboolean fp)
                g_assert (hreg < MONO_MAX_FREGS);
                g_assert (! is_global_freg (hreg));
 
-               rs->fassign [reg] = hreg;
+               rs->vassign [reg] = hreg;
                rs->fsymbolic [hreg] = reg;
                rs->ffree_mask &= ~ (regmask (hreg));
        }
        else {
                g_assert (reg >= MONO_MAX_IREGS);
                g_assert (hreg < MONO_MAX_IREGS);
+#ifndef __arm__
+               /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */
                g_assert (! is_global_ireg (hreg));
+#endif
 
-               rs->iassign [reg] = hreg;
+               rs->vassign [reg] = hreg;
                rs->isymbolic [hreg] = reg;
                rs->ifree_mask &= ~ (regmask (hreg));
        }
@@ -822,8 +798,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        MonoInst *ins;
        MonoRegState *rs = cfg->rs;
        int i, val, fpcount, ins_count;
-       RegTrack *reginfo, *reginfof;
-       RegTrack *reginfo1, *reginfo2, *reginfod;
+       RegTrack *reginfo;
        InstList *tmp, *reversed = NULL;
        const char *spec;
        GList *fspill_list = NULL;
@@ -831,15 +806,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        int fspill = 0;
        guint8 *inst_list, *mem;
 #if MONO_ARCH_USE_FPSTACK
-       gboolean need_fpstack = (use_fpstack && bb->max_freg > MONO_MAX_FREGS);
+       gboolean need_fpstack = use_fpstack;
 #endif
 
        if (!bb->code)
                return;
 
-       rs->next_vireg = bb->max_ireg;
-       rs->next_vfreg = bb->max_freg;
-       mono_regstate2_assign (rs);
+       rs->next_vreg = bb->max_vreg;
+       mono_regstate_assign (rs);
 
        rs->ifree_mask = MONO_ARCH_CALLEE_REGS;
        rs->ffree_mask = MONO_ARCH_CALLEE_FREGS;
@@ -852,35 +826,21 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        /*if (cfg->opt & MONO_OPT_COPYPROP)
                local_copy_prop (cfg, ins);*/
 
-       if (cfg->reginfo && cfg->reginfo_len < rs->next_vireg) {
+       if (cfg->reginfo && cfg->reginfo_len < rs->next_vreg) {
                cfg->reginfo = NULL;
        }
        reginfo = cfg->reginfo;
        if (!reginfo) {
-               cfg->reginfo_len = MAX (256, rs->next_vireg * 2);
+               cfg->reginfo_len = MAX (256, rs->next_vreg * 2);
                reginfo = cfg->reginfo = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len);
        } 
        else
-               g_assert (cfg->reginfo_len >= rs->next_vireg);
+               g_assert (cfg->reginfo_len >= rs->next_vreg);
 
-       if (cfg->reginfof && cfg->reginfof_len < rs->next_vfreg) {
-               cfg->reginfof = NULL;
-       }
-       reginfof = cfg->reginfof;
-       if (!reginfof) {
-               cfg->reginfof_len = MAX (256, rs->next_vfreg * 2);
-               reginfof = cfg->reginfof = mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfof_len);
-       } 
-       else
-               g_assert (cfg->reginfof_len >= rs->next_vfreg);
-
-       memset (reginfo, 0, rs->next_vireg * sizeof (RegTrack));
-       memset (reginfof, 0, rs->next_vfreg * sizeof (RegTrack));
+       memset (reginfo, 0, rs->next_vreg * sizeof (RegTrack));
 
        ins_count = 0;
        for (ins = bb->code; ins; ins = ins->next) {
-               spec = ins_spec [ins->opcode];
-
                ins_count ++;
        }
 
@@ -900,9 +860,9 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb->block_num));
        /* forward pass on the instructions to collect register liveness info */
        for (ins = bb->code; ins; ins = ins->next) {
-               spec = ins_spec [ins->opcode];
+               spec = ins_get_spec (ins->opcode);
 
-               if (G_UNLIKELY (!spec)) {
+               if (G_UNLIKELY (spec == MONO_ARCH_CPU_SPEC)) {
                        g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode));
                }
                
@@ -918,7 +878,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (spec [MONO_INST_SRC1] == 'f') {
                                spill = g_list_first (fspill_list);
                                if (spill && fpcount < MONO_ARCH_FPSTACK_SIZE) {
-                                       reginfof [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
+                                       reginfo [ins->sreg1].flags |= MONO_FP_NEEDS_LOAD;
                                        fspill_list = g_list_remove (fspill_list, spill->data);
                                } else
                                        fpcount--;
@@ -927,12 +887,12 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (spec [MONO_INST_SRC2] == 'f') {
                                spill = g_list_first (fspill_list);
                                if (spill) {
-                                       reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
+                                       reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD;
                                        fspill_list = g_list_remove (fspill_list, spill->data);
                                        if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
                                                fspill++;
                                                fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
-                                               reginfof [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
+                                               reginfo [ins->sreg2].flags |= MONO_FP_NEEDS_LOAD_SPILL;
                                        }
                                } else
                                        fpcount--;
@@ -941,7 +901,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (dreg_is_fp (spec)) {
                                if (use_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
                                        if (fpcount >= MONO_ARCH_FPSTACK_SIZE) {
-                                               reginfof [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
+                                               reginfo [ins->dreg].flags |= MONO_FP_NEEDS_SPILL;
                                                fspill++;
                                                fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
                                                fpcount--;
@@ -953,35 +913,27 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 #endif
 
                if (spec [MONO_INST_SRC1]) {
-                       if (spec [MONO_INST_SRC1] == 'f')
-                               reginfo1 = reginfof;
-                       else
-                               reginfo1 = reginfo;
-                       //reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
-                       //reginfo1 [ins->sreg1].last_use = i;
+                       //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
+                       //reginfo [ins->sreg1].last_use = i;
                        if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
                                /* The virtual register is allocated sequentially */
-                               //reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
-                               //reginfo1 [ins->sreg1 + 1].last_use = i;
-                               if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
-                                       reginfo1 [ins->sreg1 + 1].born_in = i;
+                               //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
+                               //reginfo [ins->sreg1 + 1].last_use = i;
+                               if (reginfo [ins->sreg1 + 1].born_in == 0 || reginfo [ins->sreg1 + 1].born_in > i)
+                                       reginfo [ins->sreg1 + 1].born_in = i;
                        }
                } else {
                        ins->sreg1 = -1;
                }
                if (spec [MONO_INST_SRC2]) {
-                       if (spec [MONO_INST_SRC2] == 'f')
-                               reginfo2 = reginfof;
-                       else
-                               reginfo2 = reginfo;
-                       //reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
-                       //reginfo2 [ins->sreg2].last_use = i;
+                       //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
+                       //reginfo [ins->sreg2].last_use = i;
                        if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC2])) {
                                /* The virtual register is allocated sequentially */
-                               //reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
-                               //reginfo2 [ins->sreg2 + 1].last_use = i;
-                               if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
-                                       reginfo2 [ins->sreg2 + 1].born_in = i;
+                               //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
+                               //reginfo [ins->sreg2 + 1].last_use = i;
+                               if (reginfo [ins->sreg2 + 1].born_in == 0 || reginfo [ins->sreg2 + 1].born_in > i)
+                                       reginfo [ins->sreg2 + 1].born_in = i;
                        }
                } else {
                        ins->sreg2 = -1;
@@ -989,29 +941,25 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                if (spec [MONO_INST_DEST]) {
                        int dest_dreg;
 
-                       if (dreg_is_fp (spec))
-                               reginfod = reginfof;
-                       else
-                               reginfod = reginfo;
                        if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
-                               reginfod [ins->dreg].killed_in = i;
-                       //reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
-                       //reginfod [ins->dreg].last_use = i;
-                       if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
-                               reginfod [ins->dreg].born_in = i;
+                               reginfo [ins->dreg].killed_in = i;
+                       //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
+                       //reginfo [ins->dreg].last_use = i;
+                       if (reginfo [ins->dreg].born_in == 0 || reginfo [ins->dreg].born_in > i)
+                               reginfo [ins->dreg].born_in = i;
 
                        dest_dreg = MONO_ARCH_INST_FIXED_REG (spec [MONO_INST_DEST]);
                        if (dest_dreg != -1)
-                               reginfod [ins->dreg].preferred_mask = (regmask (dest_dreg));
+                               reginfo [ins->dreg].preferred_mask = (regmask (dest_dreg));
 
                        if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) {
                                /* The virtual register is allocated sequentially */
-                               //reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
-                               //reginfod [ins->dreg + 1].last_use = i;
-                               if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
-                                       reginfod [ins->dreg + 1].born_in = i;
+                               //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
+                               //reginfo [ins->dreg + 1].last_use = i;
+                               if (reginfo [ins->dreg + 1].born_in == 0 || reginfo [ins->dreg + 1].born_in > i)
+                                       reginfo [ins->dreg + 1].born_in = i;
                                if (MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], -1) != -1)
-                                       reginfod [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
+                                       reginfo [ins->dreg + 1].preferred_mask = regpair_reg2_mask (spec [MONO_INST_DEST], -1);
                        }
                } else {
                        ins->dreg = -1;
@@ -1050,8 +998,8 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        hreg = regpair >> 24;
                                        reg = regpair & 0xffffff;
 
-                                       //reginfof [reg].prev_use = reginfof [reg].last_use;
-                                       //reginfof [reg].last_use = i;
+                                       //reginfo [reg].prev_use = reginfo [reg].last_use;
+                                       //reginfo [reg].last_use = i;
 
                                        list = g_slist_next (list);
                                }
@@ -1066,8 +1014,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
        // todo: check if we have anything left on fp stack, in verify mode?
        fspill = 0;
 
-       DEBUG (print_regtrack (reginfo, rs->next_vireg));
-       DEBUG (print_regtrack (reginfof, rs->next_vfreg));
+       DEBUG (print_regtrack (reginfo, rs->next_vreg));
        tmp = reversed;
        while (tmp) {
                int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
@@ -1078,7 +1025,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                const unsigned char *ip;
                --i;
                ins = tmp->data;
-               spec = ins_spec [ins->opcode];
+               spec = ins_get_spec (ins->opcode);
                prev_dreg = -1;
                prev_sreg2 = -1;
                clob_dreg = -1;
@@ -1086,6 +1033,9 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                dest_dreg = -1;
                dest_sreg1 = -1;
                dest_sreg2 = -1;
+               prev_sreg1 = -1;
+               dreg_high = -1;
+               sreg1_high = -1;
                dreg_mask = dreg_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
                sreg1_mask = sreg1_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
                sreg2_mask = sreg2_is_fp (spec) ? MONO_ARCH_CALLEE_FREGS : MONO_ARCH_CALLEE_REGS;
@@ -1118,7 +1068,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 #if MONO_ARCH_USE_FPSTACK
                if (need_fpstack && (spec [MONO_INST_CLOB] != 'm')) {
                        if (dreg_is_fp (spec)) {
-                               if (reginfof [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
+                               if (reginfo [ins->dreg].flags & MONO_FP_NEEDS_SPILL) {
                                        GList *spill_node;
                                        MonoInst *store;
                                        spill_node = g_list_first (fspill_list);
@@ -1132,11 +1082,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
 
                        if (spec [MONO_INST_SRC1] == 'f') {
-                               if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
+                               if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD) {
                                        MonoInst *load;
                                        MonoInst *store = NULL;
 
-                                       if (reginfof [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
+                                       if (reginfo [ins->sreg1].flags & MONO_FP_NEEDS_LOAD_SPILL) {
                                                GList *spill_node;
                                                spill_node = g_list_first (fspill_list);
                                                g_assert (spill_node);
@@ -1155,16 +1105,16 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
 
                        if (spec [MONO_INST_SRC2] == 'f') {
-                               if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
+                               if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD) {
                                        MonoInst *load;
                                        MonoInst *store = NULL;
 
-                                       if (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
+                                       if (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL) {
                                                GList *spill_node;
 
                                                spill_node = g_list_first (fspill_list);
                                                g_assert (spill_node);
-                                               if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
+                                               if (spec [MONO_INST_SRC1] == 'f' && (reginfo [ins->sreg2].flags & MONO_FP_NEEDS_LOAD_SPILL))
                                                        spill_node = g_list_next (spill_node);
        
                                                store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
@@ -1193,8 +1143,18 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        insert_before_ins (ins, tmp, copy);
                                }
                                else {
-                                       DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
-                                       assign_ireg (cfg, rs, ins->sreg2, dest_sreg2);
+                                       val = rs->vassign [ins->sreg2];
+                                       if (val == -1) {
+                                               DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins->sreg2, mono_arch_regname (dest_sreg2)));
+                                               assign_reg (cfg, rs, ins->sreg2, dest_sreg2, FALSE);
+                                       } else if (val < -1) {
+                                               /* FIXME: */
+                                               g_assert_not_reached ();
+                                       } else {
+                                               /* Argument already in hard reg, need to copy */
+                                               MonoInst *copy = create_copy_ins (cfg, dest_sreg2, val, NULL, ip, FALSE);
+                                               insert_before_ins (ins, tmp, copy);
+                                       }
                                }
                        } else {
                                int need_spill = TRUE;
@@ -1206,7 +1166,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                 * First check if dreg is assigned to dest_sreg2, since we
                                 * can't spill a dreg.
                                 */
-                               val = rs->iassign [ins->dreg];
+                               val = rs->vassign [ins->dreg];
                                if (val == dest_sreg2 && ins->dreg != ins->sreg2) {
                                        /* 
                                         * the destination register is already assigned to 
@@ -1231,7 +1191,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        insert_before_ins (ins, tmp, copy);
                                }
                                else {
-                                       val = rs->iassign [ins->sreg2];
+                                       val = rs->vassign [ins->sreg2];
                                        if (val == dest_sreg2) {
                                                /* sreg2 is already assigned to the correct register */
                                                need_spill = FALSE;
@@ -1245,7 +1205,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                if (need_spill) {
                                        DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg2]));
                                        get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg2], FALSE);
-                                       mono_regstate2_free_int (rs, dest_sreg2);
+                                       mono_regstate_free_int (rs, dest_sreg2);
                                }
 
                                if (!is_global_ireg (ins->sreg2))
@@ -1276,7 +1236,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (is_soft_reg (ins->dreg, fp) && (val >= 0) && (!(regmask (val) & dreg_mask))) {
                                /* DREG is already allocated to a register needed for sreg1 */
                                get_register_force_spilling (cfg, tmp, ins, ins->dreg, FALSE);
-                               mono_regstate2_free_int (rs, val);
+                               mono_regstate_free_int (rs, val);
                        }
                }
 
@@ -1290,13 +1250,13 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert (is_soft_reg (ins->dreg, fp));
 
                        if (dest_dreg != -1) {
-                               if (rs->iassign [ins->dreg] != dest_dreg)
+                               if (rs->vassign [ins->dreg] != dest_dreg)
                                        free_up_ireg (cfg, tmp, ins, dest_dreg);
 
                                dreg2 = ins->dreg + 1;
                                dest_dreg2 = MONO_ARCH_INST_REGPAIR_REG2 (spec [MONO_INST_DEST], dest_dreg);
                                if (dest_dreg2 != -1) {
-                                       if (rs->iassign [dreg2] != dest_dreg2)
+                                       if (rs->vassign [dreg2] != dest_dreg2)
                                                free_up_ireg (cfg, tmp, ins, dest_dreg2);
                                }
                        }
@@ -1309,10 +1269,10 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                 * The argument is already in a hard reg, but that reg is
                                 * not usable by this instruction, so allocate a new one.
                                 */
-                               val = mono_regstate2_alloc_int (rs, dreg_fixed_mask);
+                               val = mono_regstate_alloc_int (rs, dreg_fixed_mask);
                                if (val < 0)
                                        val = get_register_spilling (cfg, tmp, ins, dreg_fixed_mask, -1, fp);
-                               mono_regstate2_free_int (rs, val);
+                               mono_regstate_free_int (rs, val);
                                dest_dreg = val;
 
                                /* Fall through */
@@ -1349,16 +1309,20 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        g_assert (!fp);
                        g_assert (prev_dreg > -1);
-                       g_assert (!is_global_ireg (rs->iassign [prev_dreg]));
-                       mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->iassign [prev_dreg]);
-                       val = rs->iassign [reg2];
+                       g_assert (!is_global_ireg (rs->vassign [prev_dreg]));
+                       mask = regpair_reg2_mask (spec [MONO_INST_DEST], rs->vassign [prev_dreg]);
+#ifdef __i386__
+                       /* bug #80489 */
+                       mask &= ~regmask (X86_ECX);
+#endif
+                       val = rs->vassign [reg2];
                        if (val < 0) {
                                int spill = 0;
                                if (val < -1) {
                                        /* the register gets spilled after this inst */
                                        spill = -val -1;
                                }
-                               val = mono_regstate2_alloc_int (rs, mask);
+                               val = mono_regstate_alloc_int (rs, mask);
                                if (val < 0)
                                        val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
                                if (spill)
@@ -1366,14 +1330,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        else {
                                if (! (mask & (regmask (val)))) {
-                                       val = mono_regstate2_alloc_int (rs, mask);
+                                       val = mono_regstate_alloc_int (rs, mask);
                                        if (val < 0)
                                                val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
 
                                        /* Reallocate hreg to the correct register */
-                                       create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
+                                       create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
 
-                                       mono_regstate2_free_int (rs, rs->iassign [reg2]);
+                                       mono_regstate_free_int (rs, rs->vassign [reg2]);
                                }
                        }                                       
 
@@ -1385,11 +1349,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        if (reg_is_freeable (val, fp) && reg2 >= 0 && (reginfo [reg2].born_in >= i)) {
                                DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val), reg2));
-                               mono_regstate2_free_int (rs, val);
+                               mono_regstate_free_int (rs, val);
                        }
                }
 
-               if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && (fp ? reginfof : reginfo) [prev_dreg].born_in >= i) {
+               if ((!fp || (fp && !use_fpstack)) && prev_dreg >= 0 && is_soft_reg (prev_dreg, fp) && reginfo [prev_dreg].born_in >= i) {
                        /* 
                         * In theory, we could free up the hreg even if the vreg is alive,
                         * but branches inside bblocks force us to assign the same hreg
@@ -1397,11 +1361,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                         */
                        int dreg = rassign (cfg, prev_dreg, fp);
                        g_assert (dreg >= 0);
-                       DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, (fp ? reginfof : reginfo) [prev_dreg].born_in));
+                       DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg, fp), prev_dreg, reginfo [prev_dreg].born_in));
                        if (fp)
-                               mono_regstate2_free_float (rs, dreg);
+                               mono_regstate_free_float (rs, dreg);
                        else
-                               mono_regstate2_free_int (rs, dreg);
+                               mono_regstate_free_int (rs, dreg);
                }
 
                if ((dest_dreg != -1) && (ins->dreg != dest_dreg)) {
@@ -1434,7 +1398,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                if ((clob_reg != -1) && (!(rs->ifree_mask & (regmask (clob_reg))))) {
                        DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
                        get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg], FALSE);
-                       mono_regstate2_free_int (rs, clob_reg);
+                       mono_regstate_free_int (rs, clob_reg);
                }
 
                if (spec [MONO_INST_CLOB] == 'c') {
@@ -1461,7 +1425,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                s = regmask (j);
                                if ((clob_mask & s) && !(rs->ifree_mask & s) && (j != ins->sreg1) && (j != dreg) && (j != dreg2)) {
                                        get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [j], FALSE);
-                                       mono_regstate2_free_int (rs, j);
+                                       mono_regstate_free_int (rs, j);
                                }
                        }
 
@@ -1476,7 +1440,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        s = regmask (j);
                                        if ((clob_mask & s) && !(rs->ffree_mask & s) && (j != ins->sreg1) && (j != dreg)) {
                                                get_register_force_spilling (cfg, tmp, ins, rs->fsymbolic [j], TRUE);
-                                               mono_regstate2_free_float (rs, j);
+                                               mono_regstate_free_float (rs, j);
                                        }
                                }
                        }
@@ -1549,14 +1513,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                /* To simplify things, we allocate the same regpair to sreg1 and dreg */
                                if (dest_sreg1 != -1)
                                        g_assert (dest_sreg1 == ins->dreg);
-                               val = mono_regstate2_alloc_int (rs, regmask (ins->dreg));
+                               val = mono_regstate_alloc_int (rs, regmask (ins->dreg));
                                g_assert (val >= 0);
                                assign_reg (cfg, rs, ins->sreg1, val, fp);
 
                                DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val, fp), ins->sreg1));
 
                                g_assert ((regmask (dreg_high)) & regpair_reg2_mask (spec [MONO_INST_SRC1], ins->dreg));
-                               val = mono_regstate2_alloc_int (rs, regmask (dreg_high));
+                               val = mono_regstate_alloc_int (rs, regmask (dreg_high));
                                g_assert (val >= 0);
                                assign_reg (cfg, rs, ins->sreg1 + 1, val, fp);
 
@@ -1573,10 +1537,10 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                         * The argument is already in a hard reg, but that reg is
                                         * not usable by this instruction, so allocate a new one.
                                         */
-                                       val = mono_regstate2_alloc_int (rs, sreg1_fixed_mask);
+                                       val = mono_regstate_alloc_int (rs, sreg1_fixed_mask);
                                        if (val < 0)
                                                val = get_register_spilling (cfg, tmp, ins, sreg1_fixed_mask, -1, fp);
-                                       mono_regstate2_free_int (rs, val);
+                                       mono_regstate_free_int (rs, val);
                                        dest_sreg1 = val;
 
                                        /* Fall through to the dest_sreg1 != -1 case */
@@ -1591,7 +1555,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                if (!(rs->ifree_mask & (regmask (dest_sreg1)))) {
                                        DEBUG (printf ("\tforced spill of R%d\n", rs->isymbolic [dest_sreg1]));
                                        get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_sreg1], FALSE);
-                                       mono_regstate2_free_int (rs, dest_sreg1);
+                                       mono_regstate_free_int (rs, dest_sreg1);
                                }
                                if (is_global_ireg (ins->sreg1)) {
                                        /* The argument is already in a hard reg, need to copy */
@@ -1650,16 +1614,16 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        g_assert (!fp);
                        g_assert (prev_sreg1 > -1);
-                       g_assert (!is_global_ireg (rs->iassign [prev_sreg1]));
-                       mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->iassign [prev_sreg1]);
-                       val = rs->iassign [reg2];
+                       g_assert (!is_global_ireg (rs->vassign [prev_sreg1]));
+                       mask = regpair_reg2_mask (spec [MONO_INST_SRC1], rs->vassign [prev_sreg1]);
+                       val = rs->vassign [reg2];
                        if (val < 0) {
                                int spill = 0;
                                if (val < -1) {
                                        /* the register gets spilled after this inst */
                                        spill = -val -1;
                                }
-                               val = mono_regstate2_alloc_int (rs, mask);
+                               val = mono_regstate_alloc_int (rs, mask);
                                if (val < 0)
                                        val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
                                if (spill)
@@ -1671,14 +1635,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                        /* FIXME: */
                                        g_assert_not_reached ();
 #if 0
-                                       val = mono_regstate2_alloc_int (rs, mask);
+                                       val = mono_regstate_alloc_int (rs, mask);
                                        if (val < 0)
                                                val = get_register_spilling (cfg, tmp, ins, mask, reg2, fp);
 
                                        /* Reallocate hreg to the correct register */
-                                       create_copy_ins (cfg, rs->iassign [reg2], val, ins, ip, fp);
+                                       create_copy_ins (cfg, rs->vassign [reg2], val, ins, ip, fp);
 
-                                       mono_regstate2_free_int (rs, rs->iassign [reg2]);
+                                       mono_regstate_free_int (rs, rs->vassign [reg2]);
 #endif
                                }
                        }                                       
@@ -1706,14 +1670,14 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
                                prev_sreg2 = ins->sreg2 = reg2;
 
                                if (fp)
-                                       mono_regstate2_free_float (rs, reg2);
+                                       mono_regstate_free_float (rs, reg2);
                                else
-                                       mono_regstate2_free_int (rs, reg2);
+                                       mono_regstate_free_int (rs, reg2);
                        }
 
                        if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_SRC1])) {
                                /* Copying sreg1_high to dreg could also clobber sreg2 */
-                               if (rs->iassign [prev_sreg1 + 1] == ins->sreg2)
+                               if (rs->vassign [prev_sreg1 + 1] == ins->sreg2)
                                        /* FIXME: */
                                        g_assert_not_reached ();
 
@@ -1777,11 +1741,11 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
                /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
                        DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
-                       mono_regstate2_free_int (rs, ins->sreg1);
+                       mono_regstate_free_int (rs, ins->sreg1);
                }
                if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
                        DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
-                       mono_regstate2_free_int (rs, ins->sreg2);
+                       mono_regstate_free_int (rs, ins->sreg2);
                }*/
        
                DEBUG (mono_print_ins (i, ins));
@@ -1793,3 +1757,173 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
 
        g_list_free (fspill_list);
 }
+
+CompRelation
+mono_opcode_to_cond (int opcode)
+{
+       switch (opcode) {
+       case CEE_BEQ:
+       case OP_CEQ:
+       case OP_IBEQ:
+       case OP_ICEQ:
+       case OP_LBEQ:
+       case OP_LCEQ:
+       case OP_FBEQ:
+       case OP_FCEQ:
+       case OP_COND_EXC_EQ:
+       case OP_COND_EXC_IEQ:
+               return CMP_EQ;
+       case CEE_BNE_UN:
+       case OP_IBNE_UN:
+       case OP_LBNE_UN:
+       case OP_FBNE_UN:
+       case OP_COND_EXC_NE_UN:
+       case OP_COND_EXC_INE_UN:
+               return CMP_NE;
+       case CEE_BLE:
+       case OP_IBLE:
+       case OP_LBLE:
+       case OP_FBLE:
+               return CMP_LE;
+       case CEE_BGE:
+       case OP_IBGE:
+       case OP_LBGE:
+       case OP_FBGE:
+               return CMP_GE;
+       case CEE_BLT:
+       case OP_CLT:
+       case OP_IBLT:
+       case OP_ICLT:
+       case OP_LBLT:
+       case OP_LCLT:
+       case OP_FBLT:
+       case OP_FCLT:
+       case OP_COND_EXC_LT:
+       case OP_COND_EXC_ILT:
+               return CMP_LT;
+       case CEE_BGT:
+       case OP_CGT:
+       case OP_IBGT:
+       case OP_ICGT:
+       case OP_LBGT:
+       case OP_LCGT:
+       case OP_FBGT:
+       case OP_FCGT:
+       case OP_COND_EXC_GT:
+       case OP_COND_EXC_IGT:
+               return CMP_GT;
+
+       case CEE_BLE_UN:
+       case OP_IBLE_UN:
+       case OP_LBLE_UN:
+       case OP_FBLE_UN:
+       case OP_COND_EXC_LE_UN:
+       case OP_COND_EXC_ILE_UN:
+               return CMP_LE_UN;
+       case CEE_BGE_UN:
+       case OP_IBGE_UN:
+       case OP_LBGE_UN:
+       case OP_FBGE_UN:
+               return CMP_GE_UN;
+       case CEE_BLT_UN:
+       case OP_CLT_UN:
+       case OP_IBLT_UN:
+       case OP_ICLT_UN:
+       case OP_LBLT_UN:
+       case OP_LCLT_UN:
+       case OP_FBLT_UN:
+       case OP_FCLT_UN:
+       case OP_COND_EXC_LT_UN:
+       case OP_COND_EXC_ILT_UN:
+               return CMP_LT_UN;
+       case CEE_BGT_UN:
+       case OP_CGT_UN:
+       case OP_IBGT_UN:
+       case OP_ICGT_UN:
+       case OP_LBGT_UN:
+       case OP_LCGT_UN:
+       case OP_FCGT_UN:
+       case OP_FBGT_UN:
+       case OP_COND_EXC_GT_UN:
+       case OP_COND_EXC_IGT_UN:
+               return CMP_GT_UN;
+       default:
+               printf ("%s\n", mono_inst_name (opcode));
+               g_assert_not_reached ();
+       }
+}
+
+CompType
+mono_opcode_to_type (int opcode, int cmp_opcode)
+{
+       if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
+               return CMP_TYPE_L;
+       else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
+               return CMP_TYPE_L;
+       else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLT_UN))
+               return CMP_TYPE_I;
+       else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
+               return CMP_TYPE_I;
+       else if ((opcode >= OP_LBEQ) && (opcode <= OP_LBLT_UN))
+               return CMP_TYPE_L;
+       else if ((opcode >= OP_LCEQ) && (opcode <= OP_LCLT_UN))
+               return CMP_TYPE_L;
+       else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLT_UN))
+               return CMP_TYPE_F;
+       else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
+               return CMP_TYPE_F;
+       else if ((opcode >= OP_COND_EXC_IEQ) && (opcode <= OP_COND_EXC_ILT_UN))
+               return CMP_TYPE_I;
+       else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
+               switch (cmp_opcode) {
+               case OP_ICOMPARE:
+               case OP_ICOMPARE_IMM:
+                       return CMP_TYPE_I;
+               default:
+                       return CMP_TYPE_L;
+               }
+       } else {
+               g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
+               return 0;
+       }
+}
+
+gboolean
+mono_is_regsize_var (MonoType *t)
+{
+       if (t->byref)
+               return TRUE;
+       t = mono_type_get_underlying_type (t);
+       switch (t->type) {
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+#if SIZEOF_VOID_P == 8
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+#endif
+               return TRUE;
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:
+               return TRUE;
+       case MONO_TYPE_GENERICINST:
+               if (!mono_type_generic_inst_is_valuetype (t))
+                       return TRUE;
+               return FALSE;
+       case MONO_TYPE_VALUETYPE:
+               return FALSE;
+       }
+       return FALSE;
+}