2009-05-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-mips.c
index b1463af0a0ac15cc33bb2f948a8c7d8fcc26f1ca..c29b5d0437e5a11c124bfb32578235d1fa797d36 100644 (file)
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 
+#include <mono/arch/mips/mips-codegen.h>
+
 #include "mini-mips.h"
 #include "cpu-mips.h"
 #include "trace.h"
 #include "ir-emit.h"
 
-#warning "The mips backend is still being ported to the linear IR."
-
 #define SAVE_FP_REGS           0
 #define SAVE_ALL_REGS          0
 #define EXTRA_STACK_SPACE      0       /* suppresses some s-reg corruption issues */
-#define LONG_BRANCH            0       /* needed for yyparse in mcs */
+#define LONG_BRANCH            1       /* needed for yyparse in mcs */
 
 #define SAVE_LMF               1
 #define ALWAYS_USE_FP          1
 #define ALWAYS_SAVE_RA         1       /* call-handler & switch currently clobber ra */
 
 #define PROMOTE_R4_TO_R8       1       /* promote single values in registers to doubles */
+#define USE_MUL                        1       /* use mul instead of mult/mflo for multiply */
 
 enum {
        TLS_MODE_DETECT,
@@ -93,8 +94,12 @@ static int monodomain_key = -1;
                mono_bblock_add_inst (cfg->cbb, inst); \
        } while (0)
 
-#define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) || ((ins)->opcode == OP_ICOMPARE)))
-#define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) || ((ins)->opcode == OP_ICOMPARE_IMM)))
+#define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
+                                      || ((ins)->opcode == OP_ICOMPARE) \
+                                      || ((ins)->opcode == OP_LCOMPARE)))
+#define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
+                                          || ((ins)->opcode == OP_ICOMPARE_IMM) \
+                                          || ((ins)->opcode == OP_LCOMPARE_IMM)))
 
 #define INS_REWRITE(ins, op, _s1, _s2) do { \
                        int s1 = _s1;                   \
@@ -152,6 +157,11 @@ typedef struct {
 
 void patch_lui_addiu(guint32 *ip, guint32 val);
 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
+guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
+void mips_adjust_stackframe(MonoCompile *cfg);
+void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
+MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+
 
 void
 mono_arch_flush_icache (guint8 *code, gint size)
@@ -175,9 +185,13 @@ static guint8 *
 mips_emit_exc_by_name(guint8 *code, const char *name)
 {
        guint32 addr;
+       MonoClass *exc_class;
+
+       exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
+       g_assert (exc_class);
 
-       mips_load_const (code, mips_a0, name);
-       addr = (guint32) mono_arch_get_throw_exception_by_name ();
+       mips_load_const (code, mips_a0, exc_class->type_token);
+       addr = (guint32) mono_arch_get_throw_corlib_exception ();
        mips_load_const (code, mips_t9, addr);
        mips_jalr (code, mips_t9, mips_ra);
        mips_nop (code);
@@ -186,10 +200,42 @@ mips_emit_exc_by_name(guint8 *code, const char *name)
 }
 
 
+guint8 *
+mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
+{
+       if (mips_is_imm16 (v))
+               mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
+       else {
+#ifdef SIZEOF_REGISTER == 8
+               if (v != (long) v) {
+                       /* v is not a sign-extended 32-bit value */
+                       mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
+                       mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
+                       mips_dsll (code, dreg, dreg, 16);
+                       mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
+                       mips_dsll (code, dreg, dreg, 16);
+                       mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
+                       return code;
+               }
+#endif
+               if (((guint32)v) & (1 << 15)) {
+                       mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
+               }
+               else {
+                       mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
+               }
+               if (((guint32)v) & 0xffff)
+                       mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
+       }
+       return code;
+}
+
 guint8 *
 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
 {
+#if LONG_BRANCH
        int br_offset = 5;
+#endif
 
        g_assert (ins);
 #if LONG_BRANCH
@@ -340,6 +386,7 @@ mips_patch (guint32 *code, guint32 target)
        }
 }
 
+#if 0
 static int
 offsets_from_pthread_key (guint32 key, int *offset2)
 {
@@ -348,9 +395,11 @@ offsets_from_pthread_key (guint32 key, int *offset2)
        *offset2 = idx2 * sizeof (gpointer);
        return 284 + idx1 * sizeof (gpointer);
 }
+#endif
 
 const char*
 mono_arch_regname (int reg) {
+#if _MIPS_SIM == _ABIO32
        static const char * rnames[] = {
                "zero", "at", "v0", "v1",
                "a0", "a1", "a2", "a3",
@@ -361,6 +410,18 @@ mono_arch_regname (int reg) {
                "t8", "t9", "k0", "k1",
                "gp", "sp", "fp", "ra"
        };
+#elif _MIPS_SIM == _ABIN32
+       static const char * rnames[] = {
+               "zero", "at", "v0", "v1",
+               "a0", "a1", "a2", "a3",
+               "a4", "a5", "a6", "a7",
+               "t0", "t1", "t2", "t3",
+               "s0", "s1", "s2", "s3",
+               "s4", "s5", "s6", "s7",
+               "t8", "t9", "k0", "k1",
+               "gp", "sp", "fp", "ra"
+       };
+#endif
        if (reg >= 0 && reg < 32)
                return rnames [reg];
        return "unknown";
@@ -510,6 +571,10 @@ is_regsize_var (MonoType *t) {
        switch (t->type) {
        case MONO_TYPE_I4:
        case MONO_TYPE_U4:
+#if (SIZEOF_REGISTER == 8)
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+#endif
        case MONO_TYPE_I:
        case MONO_TYPE_U:
        case MONO_TYPE_PTR:
@@ -593,12 +658,13 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
 static void
 args_onto_stack (CallInfo *info)
 {
-       g_assert(!info->on_stack);
-       g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
+       g_assert (!info->on_stack);
+       g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
        info->on_stack = TRUE;
        info->stack_size = MIPS_STACK_PARAM_OFFSET;
 }
 
+#if _MIPS_SIM == _ABIO32
 /*
  * O32 calling convention version
  */
@@ -632,7 +698,7 @@ add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
 
        /* Now, place the argument */
        if (info->on_stack) {
-               g_assert(info->stack_size % 4 == 0);
+               g_assert (info->stack_size % 4 == 0);
                info->stack_size += (info->stack_size % 8);
 
                ainfo->regtype = RegTypeBase;
@@ -726,6 +792,113 @@ add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
        }
        info->stack_size += 8;
 }
+#elif _MIPS_SIM == _ABIN32
+/*
+ * N32 calling convention version
+ */
+
+static void
+add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
+       /* First, see if we need to drop onto the stack */
+       if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+               args_onto_stack (info);
+
+       /* Now, place the argument */
+       if (info->on_stack) {
+               ainfo->regtype = RegTypeBase;
+               ainfo->reg = mips_sp; /* in the caller */
+               ainfo->offset = info->stack_size;
+               info->stack_size += SIZEOF_REGISTER;
+       }
+       else {
+               ainfo->regtype = RegTypeGeneral;
+               ainfo->reg = info->gr;
+               info->gr += 1;
+               info->gr_passed = TRUE;
+       }
+}
+
+static void
+add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
+       /* First, see if we need to drop onto the stack */
+       if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+               args_onto_stack (info);
+
+       /* Now, place the argument */
+       if (info->on_stack) {
+               g_assert (info->stack_size % 4 == 0);
+               info->stack_size += (info->stack_size % 8);
+
+               ainfo->regtype = RegTypeBase;
+               ainfo->reg = mips_sp; /* in the caller */
+               ainfo->offset = info->stack_size;
+               info->stack_size += SIZEOF_REGISTER;
+       }
+       else {
+               g_assert (info->gr <= MIPS_LAST_ARG_REG);
+
+               ainfo->regtype = RegTypeGeneral;
+               ainfo->reg = info->gr;
+               info->gr += 1;
+               info->gr_passed = TRUE;
+       }
+}
+
+static void
+add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
+       /* First, see if we need to drop onto the stack */
+       if (!info->on_stack) {
+               if (info->gr > MIPS_LAST_ARG_REG)
+                       args_onto_stack (info);
+               else if (info->fr > MIPS_LAST_FPARG_REG)
+                       args_onto_stack (info);
+       }
+
+       /* Now, place the argument */
+       if (info->on_stack) {
+               ainfo->regtype = RegTypeBase;
+               ainfo->reg = mips_sp; /* in the caller */
+               ainfo->offset = info->stack_size;
+               info->stack_size += FREG_SIZE;
+       }
+       else {
+               ainfo->regtype = RegTypeFP;
+               ainfo->reg = info->fr;
+               info->fr += 1;
+               /* FP and GP slots do not overlap */
+               info->gr += 1;
+       }
+}
+
+static void
+add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
+       /* First, see if we need to drop onto the stack */
+       if (!info->on_stack) {
+               if (info->gr > MIPS_LAST_ARG_REG)
+                       args_onto_stack (info);
+               else if (info->fr > MIPS_LAST_FPARG_REG)
+                       args_onto_stack (info);
+       }
+
+       /* Now, place the argument */
+       if (info->on_stack) {
+               g_assert(info->stack_size % 4 == 0);
+               info->stack_size += (info->stack_size % 8);
+
+               ainfo->regtype = RegTypeBase;
+               ainfo->reg = mips_sp; /* in the caller */
+               ainfo->offset = info->stack_size;
+               info->stack_size += FREG_SIZE;
+       }
+       else {
+               ainfo->regtype = RegTypeFP;
+               ainfo->reg = info->fr;
+               info->fr += 1;
+               /* FP and GP slots do not overlap */
+               info->gr += 1;
+       }
+}
+#endif
 
 static CallInfo*
 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
@@ -843,8 +1016,8 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                                  cinfo->stack_size, alignment);
 #endif
                        nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
-                       g_assert(cinfo->args [n].size == 0);
-                       g_assert(cinfo->args [n].vtsize == 0);
+                       g_assert (cinfo->args [n].size == 0);
+                       g_assert (cinfo->args [n].vtsize == 0);
                        for (j = 0; j < nwords; ++j) {
                                if (j == 0) {
                                        add_int32_arg (cinfo, &cinfo->args [n]);
@@ -998,7 +1171,9 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        int i, offset, size, align, curinst;
        int frame_reg = mips_sp;
        guint32 iregs_to_save = 0;
+#if SAVE_FP_REGS
        guint32 fregs_to_restore;
+#endif
 
        /* spill down, we'll fix it in a separate pass */
        // cfg->flags |= MONO_CFG_HAS_SPILLUP;
@@ -1123,7 +1298,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        if (iregs_to_save) {
                for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
                        if (iregs_to_save & (1 << i)) {
-                               offset += sizeof (gulong);
+                               offset += SIZEOF_REGISTER;
                        }
                }
        }
@@ -1139,19 +1314,21 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        if (fregs_to_restore) {
                for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
                        if (fregs_to_restore & (1 << i)) {
-                               offset += sizeof (double);
+                               offset += sizeof(double);
                        }
                }
        }
 #endif
 
+#if _MIPS_SIM == _ABIO32
        /* Now add space for saving the ra */
-       offset += 4;
+       offset += SIZEOF_VOID_P;
 
        /* change sign? */
        offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
        cfg->stack_offset = offset;
        cfg->arch.local_alloc_offset = cfg->stack_offset;
+#endif
 
        /*
         * Now allocate stack slots for the int arg regs (a0 - a3)
@@ -1165,7 +1342,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                cfg->vret_addr->inst_c0 = mips_a0;
                cfg->vret_addr->inst_offset = offset;
                cfg->vret_addr->inst_basereg = frame_reg;
-               offset += 4;
+               offset += SIZEOF_REGISTER;
        }
 
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
@@ -1181,9 +1358,9 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        inst->opcode = OP_REGOFFSET;
                        size = mono_type_size (arg_type, &align);
 
-                       if (size < 4) {
-                               size = 4;
-                               align = 4;
+                       if (size < SIZEOF_REGISTER) {
+                               size = SIZEOF_REGISTER;
+                               align = SIZEOF_REGISTER;
                        }
                        inst->inst_basereg = frame_reg;
                        offset = (offset + align - 1) & ~(align - 1);
@@ -1194,9 +1371,10 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
                }
                else {
-                       /* Even a0-a3 get stack slots */
-                       size = sizeof (gpointer);
-                       align = sizeof (gpointer);
+#if _MIPS_SIM == _ABIO32
+                       /* o32: Even a0-a3 get stack slots */
+                       size = SIZEOF_REGISTER;
+                       align = SIZEOF_REGISTER;
                        inst->inst_basereg = frame_reg;
                        offset = (offset + align - 1) & ~(align - 1);
                        inst->inst_offset = offset;
@@ -1204,8 +1382,18 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
                                cfg->sig_cookie += size;
                        // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
+#endif
                }
        }
+#if _MIPS_SIM == _ABIN32
+       /* Now add space for saving the ra */
+       offset += SIZEOF_VOID_P;
+
+       /* change sign? */
+       offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
+       cfg->stack_offset = offset;
+       cfg->arch.local_alloc_offset = cfg->stack_offset;
+#endif
 }
 
 void
@@ -1281,6 +1469,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                }
                in = call->args [i];
                if (ainfo->regtype == RegTypeGeneral) {
+#if SIZEOF_REGISTER == 4
                        if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
                                MONO_INST_NEW (cfg, ins, OP_MOVE);
                                ins->dreg = mono_alloc_ireg (cfg);
@@ -1293,7 +1482,9 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                ins->sreg1 = in->dreg + 2;
                                MONO_ADD_INS (cfg->cbb, ins);
                                mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
-                       } else if (!t->byref && (t->type == MONO_TYPE_R4)) {
+                       } else
+#endif
+                       if (!t->byref && (t->type == MONO_TYPE_R4)) {
                                int freg;
 
 #if PROMOTE_R4_TO_R8
@@ -1373,7 +1564,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                int dreg = mono_alloc_freg (cfg);
 
                                if (ainfo->size == 4) {
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
                                } else {
                                        MONO_INST_NEW (cfg, ins, OP_FMOVE);
                                        ins->dreg = dreg;
@@ -1421,7 +1612,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 #endif
        call->stack_usage = cinfo->stack_usage;
        cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
-       cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
+#if _MIPS_SIM == _ABIO32
+       /* a0-a3 always present */
+       cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
+#endif
        cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
        cfg->flags |= MONO_CFG_HAS_CALLS;
        /* 
@@ -1456,10 +1650,10 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
                        dreg = mono_alloc_ireg (cfg);
                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
                        mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
-                       soffset += sizeof (gpointer);
+                       soffset += SIZEOF_REGISTER;
                }
                if (ovf_size != 0) {
-                       mini_emit_memcpy (cfg, mips_fp, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+                       mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
                }
        } else if (ainfo->regtype == RegTypeFP) {
                int tmpr = mono_alloc_freg (cfg);
@@ -1503,6 +1697,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
                        mono_method_signature (method)->ret);
 
        if (!ret->byref) {
+#if (SIZEOF_REGISTER == 4)
                if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
                        MonoInst *ins;
 
@@ -1512,12 +1707,13 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
                        MONO_ADD_INS (cfg->cbb, ins);
                        return;
                }
+#endif
                if (ret->type == MONO_TYPE_R8) {
                        MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
                        return;
                }
                if (ret->type == MONO_TYPE_R4) {
-                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, cfg->ret->dreg, val->dreg);
+                       MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
                        return;
                }
        }
@@ -1838,6 +2034,18 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
                break;
 
        case OP_LADD_OVF_UN:
+               tmp1 = mono_alloc_ireg (cfg);
+               tmp2 = mono_alloc_ireg (cfg);
+
+               MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
+               MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
+               MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
+               MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
+               ins->opcode = OP_NOP;
+               break;
+
        case OP_LMUL_OVF:
        case OP_LMUL_OVF_UN:
                mono_print_ins (ins);
@@ -1936,10 +2144,23 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
        case OP_LBGT_UN:
        case OP_LBLE_UN:
        case OP_LBLT_UN:
+               mono_print_ins (ins);
+               g_assert_not_reached ();
+#if 0
        case OP_LCONV_TO_R8_2:
        case OP_LCONV_TO_R4_2:
        case OP_LCONV_TO_R_UN_2:
+#endif
        case OP_LCONV_TO_OVF_I4_2:
+               tmp1 = mono_alloc_ireg (cfg);
+
+               /* Overflows if reg2 != sign extension of reg1 */
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
+               MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
+               ins->opcode = OP_NOP;
+               break;
+
        case OP_LMIN_UN:
        case OP_LMAX_UN:
        case OP_LMIN:
@@ -1999,6 +2220,15 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
                ins->opcode = OP_NOP;
                break;
 
+       case OP_IADD_OVF_UN:
+               tmp1 = mono_alloc_ireg (cfg);
+
+               MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
+               MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
+               MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
+               ins->opcode = OP_NOP;
+               break;
+
        case OP_ISUB_OVF:
                tmp1 = mono_alloc_ireg (cfg);
                tmp2 = mono_alloc_ireg (cfg);
@@ -2039,73 +2269,6 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
                MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
                ins->opcode = OP_NOP;
                break;
-
-       case OP_ICONV_TO_R_UN: {
-               static const guint64 adjust_val = 0x4330000000000000ULL;
-               int msw_reg = mono_alloc_ireg (cfg);
-               int adj_reg = mono_alloc_freg (cfg);
-               int tmp_reg = mono_alloc_freg (cfg);
-               int basereg = mips_sp;
-               int offset = -8;
-
-               MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
-               if (!mips_is_imm16 (offset + 4)) {
-                       basereg = mono_alloc_ireg (cfg);
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
-               }
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
-               MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
-               MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
-               ins->opcode = OP_NOP;
-               break;
-       }
-       case OP_ICONV_TO_R4:
-       case OP_ICONV_TO_R8: {
-               /* FIXME: change precision for OP_ICONV_TO_R4 */
-               static const guint64 adjust_val = 0x4330000080000000ULL;
-               int msw_reg = mono_alloc_ireg (cfg);
-               int xored = mono_alloc_ireg (cfg);
-               int adj_reg = mono_alloc_freg (cfg);
-               int tmp_reg = mono_alloc_freg (cfg);
-               int basereg = mips_sp;
-               int offset = -8;
-
-               if (!mips_is_imm16 (offset + 4)) {
-                       basereg = mono_alloc_ireg (cfg);
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
-               }
-               MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
-               MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
-               MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
-               if (ins->opcode == OP_ICONV_TO_R4)
-                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
-               ins->opcode = OP_NOP;
-               break;
-       }
-#if 0
-       case OP_CKFINITE: {
-               int msw_reg = mono_alloc_ireg (cfg);
-               int basereg = mips_sp;
-               int offset = -8;
-
-               if (!mips_is_imm16 (offset + 4)) {
-                       basereg = mono_alloc_ireg (cfg);
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
-               }
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
-               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
-               MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
-               ins->opcode = OP_NOP;
-               break;
-       }
-#endif
        }
 
 }
@@ -2124,6 +2287,8 @@ map_to_reg_reg_op (int op)
                return OP_COMPARE;
        case OP_ICOMPARE_IMM:
                return OP_ICOMPARE;
+       case OP_LCOMPARE_IMM:
+               return OP_LCOMPARE;
        case OP_ADDCC_IMM:
                return OP_IADDCC;
        case OP_ADC_IMM:
@@ -2176,6 +2341,8 @@ map_to_reg_reg_op (int op)
                return OP_STOREI2_MEMBASE_REG;
        case OP_STOREI4_MEMBASE_IMM:
                return OP_STOREI4_MEMBASE_REG;
+       case OP_STOREI8_MEMBASE_IMM:
+               return OP_STOREI8_MEMBASE_REG;
        }
        return mono_op_imm_to_op (op);
 }
@@ -2269,6 +2436,7 @@ loop_start:
                switch (ins->opcode) {
                case OP_COMPARE:
                case OP_ICOMPARE:
+               case OP_LCOMPARE:
                        next = ins->next;
                        /* Branch opts can eliminate the branch */
                        if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
@@ -2279,6 +2447,7 @@ loop_start:
 
                case OP_COMPARE_IMM:
                case OP_ICOMPARE_IMM:
+               case OP_LCOMPARE_IMM:
                        next = ins->next;
                        /* Branch opts can eliminate the branch */
                        if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
@@ -2299,6 +2468,8 @@ loop_start:
                                ins->opcode = OP_COMPARE;
                        else if (ins->opcode == OP_ICOMPARE_IMM)
                                ins->opcode = OP_ICOMPARE;
+                       else if (ins->opcode == OP_LCOMPARE_IMM)
+                               ins->opcode = OP_LCOMPARE;
                        goto loop_start;
 
                case OP_IDIV_UN_IMM:
@@ -2363,26 +2534,8 @@ loop_start:
                        }
                        break;
 
-               case OP_FCOMPARE:
-                       next = ins->next;
-                       /* Branch opts can eliminate the branch */
-                       if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
-                               ins->opcode = OP_NOP;
-                               break;
-                       }
-                       g_assert(next);
-
-                       /*
-                        * remap compare/branch and compare/set
-                        * to MIPS specific opcodes.
-                        */
-                       ins->opcode = OP_NOP;
-                       next->opcode = map_to_mips_op (next->opcode);
-                       next->sreg1 = ins->sreg1;
-                       next->sreg2 = ins->sreg2;
-                       break;
-
                case OP_SUB_IMM:
+               case OP_ISUB_IMM:
                        if (!mips_is_imm16 (-ins->inst_imm)) {
                                NEW_INS (cfg, last_ins, temp, OP_ICONST);
                                temp->inst_c0 = ins->inst_imm;
@@ -2392,17 +2545,8 @@ loop_start:
                        }
                        break;
 
-               case OP_SBB_IMM:
-               case OP_SUBCC_IMM:
-               case OP_ADC_IMM:
-                       NEW_INS (cfg, last_ins, temp, OP_ICONST);
-                       temp->inst_c0 = ins->inst_imm;
-                       temp->dreg = mono_alloc_ireg (cfg);
-                       ins->sreg2 = temp->dreg;
-                       ins->opcode = map_to_reg_reg_op (ins->opcode);
-                       break;
-
                case OP_MUL_IMM:
+               case OP_IMUL_IMM:
                        if (ins->inst_imm == 1) {
                                ins->opcode = OP_MOVE;
                                break;
@@ -2418,13 +2562,19 @@ loop_start:
                                ins->inst_imm = imm;
                                break;
                        }
-                       if (!mips_is_imm16 (ins->inst_imm)) {
-                               NEW_INS (cfg, last_ins, temp, OP_ICONST);
-                               temp->inst_c0 = ins->inst_imm;
-                               temp->dreg = mono_alloc_ireg (cfg);
-                               ins->sreg2 = temp->dreg;
-                               ins->opcode = map_to_reg_reg_op (ins->opcode);
-                       }
+                       NEW_INS (cfg, last_ins, temp, OP_ICONST);
+                       temp->inst_c0 = ins->inst_imm;
+                       temp->dreg = mono_alloc_ireg (cfg);
+                       ins->sreg2 = temp->dreg;
+                       ins->opcode = map_to_reg_reg_op (ins->opcode);
+                       break;
+
+               case OP_LOCALLOC_IMM:
+                       NEW_INS (cfg, last_ins, temp, OP_ICONST);
+                       temp->inst_c0 = ins->inst_imm;
+                       temp->dreg = mono_alloc_ireg (cfg);
+                       ins->sreg1 = temp->dreg;
+                       ins->opcode = OP_LOCALLOC;
                        break;
 
                case OP_LOAD_MEMBASE:
@@ -2460,6 +2610,7 @@ loop_start:
                case OP_STOREI1_MEMBASE_IMM:
                case OP_STOREI2_MEMBASE_IMM:
                case OP_STOREI4_MEMBASE_IMM:
+               case OP_STOREI8_MEMBASE_IMM:
                        if (!ins->inst_imm) {
                                ins->sreg1 = mips_zero;
                                ins->opcode = map_to_reg_reg_op (ins->opcode);
@@ -2475,6 +2626,26 @@ loop_start:
                        }
                        break;
 
+               case OP_FCOMPARE:
+                       next = ins->next;
+                       /* Branch opts can eliminate the branch */
+                       if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
+                               ins->opcode = OP_NOP;
+                               break;
+                       }
+                       g_assert(next);
+
+                       /*
+                        * remap compare/branch and compare/set
+                        * to MIPS specific opcodes.
+                        */
+                       ins->opcode = OP_NOP;
+                       next->opcode = map_to_mips_op (next->opcode);
+                       next->sreg1 = ins->sreg1;
+                       next->sreg2 = ins->sreg2;
+                       break;
+
+#if 0
                case OP_R8CONST:
                case OP_R4CONST:
                        NEW_INS (cfg, last_ins, temp, OP_ICONST);
@@ -2488,7 +2659,7 @@ loop_start:
                         * later optimize to use lis + load_membase
                         */
                        goto loop_start;
-
+#endif
                case OP_IBEQ:
                        g_assert (ins_is_compare(last_ins));
                        INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
@@ -2637,14 +2808,14 @@ loop_start:
                case OP_COND_EXC_GE_UN:
                case OP_COND_EXC_IGE_UN:
                        g_assert (ins_is_compare(last_ins));
-                       INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
+                       INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
                        MONO_DELETE_INS(bb, last_ins);
                        break;
 
                case OP_COND_EXC_GT_UN:
                case OP_COND_EXC_IGT_UN:
                        g_assert (ins_is_compare(last_ins));
-                       INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
+                       INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
                        MONO_DELETE_INS(bb, last_ins);
                        break;
 
@@ -2658,7 +2829,7 @@ loop_start:
                case OP_COND_EXC_LT_UN:
                case OP_COND_EXC_ILT_UN:
                        g_assert (ins_is_compare(last_ins));
-                       INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
+                       INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
                        MONO_DELETE_INS(bb, last_ins);
                        break;
 
@@ -2740,7 +2911,7 @@ loop_start:
 static guchar*
 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
 {
-       /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
+       /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
 #if 1
        mips_truncwd (code, mips_ftemp, sreg);
 #else
@@ -2770,7 +2941,7 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
 /*
  * emit_load_volatile_arguments:
  *
- *  Load volatile arguments from the stack to the original input registers.
+ * Load volatile arguments from the stack to the original input registers.
  * Required before a tail call.
  */
 static guint8 *
@@ -2795,7 +2966,7 @@ emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
                inst = cfg->args [i];
                if (inst->opcode == OP_REGVAR) {
                        if (ainfo->regtype == RegTypeGeneral)
-                               mips_move (code, ainfo->reg, inst->dreg);
+                               MIPS_MOVE (code, ainfo->reg, inst->dreg);
                        else if (ainfo->regtype == RegTypeFP)
                                g_assert_not_reached();
                        else if (ainfo->regtype == RegTypeBase) {
@@ -2828,8 +2999,14 @@ emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
                                /* do nothing */
                        } else if (ainfo->regtype == RegTypeFP) {
                                g_assert (mips_is_imm16 (inst->inst_offset));
-                               if (ainfo->size == 8)
+                               if (ainfo->size == 8) {
+#if _MIPS_SIM == _ABIO32
+                                       mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
+                                       mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
+#elif _MIPS_SIM == _ABIN32
                                        mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+#endif
+                               }
                                else if (ainfo->size == 4)
                                        mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
                                else
@@ -2842,7 +3019,7 @@ emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
                                g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
                                for (i = 0; i < ainfo->size; ++i) {
                                        mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
-                                       doffset += sizeof (gpointer);
+                                       doffset += SIZEOF_REGISTER;
                                }
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
                                g_assert (mips_is_imm16 (inst->inst_offset));
@@ -3000,6 +3177,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
                        }
                        break;
+               case OP_STOREI8_MEMBASE_IMM:
+                       mips_load_const (code, mips_temp, ins->inst_imm);
+                       if (mips_is_imm16 (ins->inst_offset)) {
+                               mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
+                       } else {
+                               mips_load_const (code, mips_at, ins->inst_offset);
+                               mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
+                       }
+                       break;
                case OP_STORE_MEMBASE_IMM:
                case OP_STOREI4_MEMBASE_IMM:
                        mips_load_const (code, mips_temp, ins->inst_imm);
@@ -3038,11 +3224,29 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mips_sw (code, ins->sreg1, mips_at, 0);
                        }
                        break;
+               case OP_STOREI8_MEMBASE_REG:
+                       if (mips_is_imm16 (ins->inst_offset)) {
+                               mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+                       } else {
+                               mips_load_const (code, mips_at, ins->inst_offset);
+                               mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
+                               mips_sd (code, ins->sreg1, mips_at, 0);
+                       }
+                       break;
                case OP_LOADU4_MEM:
                        g_assert_not_reached ();
                        //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
                        //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
                        break;
+               case OP_LOADI8_MEMBASE:
+                       if (mips_is_imm16 (ins->inst_offset)) {
+                               mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+                       } else {
+                               mips_load_const (code, mips_at, ins->inst_offset);
+                               mips_addu (code, mips_at, mips_at, ins->inst_basereg);
+                               mips_ld (code, ins->dreg, mips_at, 0);
+                       }
+                       break;
                case OP_LOAD_MEMBASE:
                case OP_LOADI4_MEMBASE:
                case OP_LOADU4_MEMBASE:
@@ -3125,40 +3329,52 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_IADD:
                        mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_LADD:
+                       mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
+
                case OP_ADD_IMM:
                case OP_IADD_IMM:
-                       if (mips_is_imm16 (ins->inst_imm)) {
-                               mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
-                       } else {
-                               mips_load_const (code, mips_at, ins->inst_imm);
-                               mips_addu (code, ins->dreg, ins->sreg1, mips_at);
-                       }
+                       g_assert (mips_is_imm16 (ins->inst_imm));
+                       mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
+                       break;
+               case OP_LADD_IMM:
+                       g_assert (mips_is_imm16 (ins->inst_imm));
+                       mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        break;
+
                case OP_ISUB:
                        mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_LSUB:
+                       mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
+
                case OP_ISUB_IMM:
                case OP_SUB_IMM:
                        // we add the negated value
-                       if (mips_is_imm16 (-ins->inst_imm))
-                               mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
-                       else {
-                               mips_load_const (code, mips_at, ins->inst_imm);
-                               mips_subu (code, ins->dreg, ins->sreg1, mips_at);
-                       }
+                       g_assert (mips_is_imm16 (-ins->inst_imm));
+                       mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
                        break;
+
+               case OP_LSUB_IMM:
+                       // we add the negated value
+                       g_assert (mips_is_imm16 (-ins->inst_imm));
+                       mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
+                       break;
+
                case OP_IAND:
+               case OP_LAND:
                        mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+
                case OP_AND_IMM:
                case OP_IAND_IMM:
-                       if (mips_is_imm16 (ins->inst_imm)) {
-                               mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
-                       } else {
-                               mips_load_const (code, mips_at, ins->inst_imm);
-                               mips_and (code, ins->dreg, ins->sreg1, mips_at);
-                       }
+               case OP_LAND_IMM:
+                       g_assert (!(ins->inst_imm & 0xffff0000));
+                       mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        break;
+
                case OP_IDIV:
                case OP_IREM: {
                        guint32 *divisor_is_m1;
@@ -3166,7 +3382,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* */
                        mips_addiu (code, mips_at, mips_zero, 0xffff);
-                       divisor_is_m1 = (guint32 *)code;
+                       divisor_is_m1 = (guint32 *)(void *)code;
                        mips_bne (code, ins->sreg2, mips_at, 0);
                        mips_nop (code);
 
@@ -3176,7 +3392,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_patch (divisor_is_m1, (guint32)code);
 
                        /* Put divide in branch delay slot (NOT YET) */
-                       divisor_is_zero = (guint32 *)code;
+                       divisor_is_zero = (guint32 *)(void *)code;
                        mips_bne (code, ins->sreg2, mips_zero, 0);
                        mips_nop (code);
 
@@ -3251,25 +3467,41 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_ISHR:
                        mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_LSHR:
+                       mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
                case OP_SHR_IMM:
                case OP_ISHR_IMM:
                        mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
                        break;
+               case OP_LSHR_IMM:
+                       mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
+                       break;
                case OP_SHR_UN_IMM:
                case OP_ISHR_UN_IMM:
                        mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
                        break;
+               case OP_LSHR_UN_IMM:
+                       mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
+                       break;
                case OP_ISHR_UN:
                        mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_LSHR_UN:
+                       mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
                case OP_INOT:
+               case OP_LNOT:
                        mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
                        break;
                case OP_INEG:
                        mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
                        break;
+               case OP_LNEG:
+                       mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
+                       break;
                case OP_IMUL:
-#if 1
+#if USE_MUL
                        mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
 #else
                        mips_mult (code, ins->sreg1, ins->sreg2);
@@ -3278,18 +3510,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_nop (code);
 #endif
                        break;
-               case OP_MUL_IMM:
-               case OP_IMUL_IMM:
-                       mips_load_const (code, mips_at, ins->inst_imm);
-#if 1
-                       mips_mul (code, ins->dreg, ins->sreg1, mips_at);
-#else
-                       mips_mult (code, ins->sreg1, mips_at);
+#if SIZEOF_REGISTER == 8
+               case OP_LMUL:
+                       mips_dmult (code, ins->sreg1, ins->sreg2);
                        mips_mflo (code, ins->dreg);
-                       mips_nop (code);
-                       mips_nop (code);
-#endif
                        break;
+#endif
                case OP_IMUL_OVF: {
                        guint32 *patch;
                        mips_mult (code, ins->sreg1, ins->sreg2);
@@ -3320,6 +3546,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_ICONST:
                        mips_load_const (code, ins->dreg, ins->inst_c0);
                        break;
+#if SIZEOF_REGISTER == 8
+               case OP_I8CONST:
+                       mips_load_const (code, ins->dreg, ins->inst_c0);
+                       break;
+#endif
                case OP_AOTCONST:
                        mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
                        mips_load (code, ins->dreg, 0);
@@ -3328,6 +3559,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_MIPS_MTC1S:
                        mips_mtc1 (code, ins->dreg, ins->sreg1);
                        break;
+               case OP_MIPS_MTC1S_2:
+                       mips_mtc1 (code, ins->dreg, ins->sreg1);
+                       mips_mtc1 (code, ins->dreg+1, ins->sreg2);
+                       break;
                case OP_MIPS_MFC1S:
                        mips_mfc1 (code, ins->dreg, ins->sreg1);
                        break;
@@ -3335,30 +3570,45 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_dmtc1 (code, ins->dreg, ins->sreg1);
                        break;
                case OP_MIPS_MFC1D:
+#if 0
                        mips_dmfc1 (code, ins->dreg, ins->sreg1);
+#else
+                       mips_mfc1 (code, ins->dreg+1, ins->sreg1);
+                       mips_mfc1 (code, ins->dreg, ins->sreg1+1);
+#endif
                        break;
 
                case OP_ICONV_TO_I4:
                case OP_ICONV_TO_U4:
                case OP_MOVE:
                        if (ins->dreg != ins->sreg1)
-                               mips_move (code, ins->dreg, ins->sreg1);
+                               MIPS_MOVE (code, ins->dreg, ins->sreg1);
+                       break;
+#if SIZEOF_REGISTER == 8
+               case OP_ZEXT_I4:
+                       mips_dsll (code, ins->dreg, ins->sreg1, 32);
+                       mips_dsrl (code, ins->dreg, ins->dreg, 32);
                        break;
+               case OP_SEXT_I4:
+                       mips_dsll (code, ins->dreg, ins->sreg1, 32);
+                       mips_dsra (code, ins->dreg, ins->dreg, 32);
+                       break;
+#endif
                case OP_SETLRET:
                        /* Get sreg1 into v1, sreg2 into v0 */
 
                        if (ins->sreg1 == mips_v0) {
                                if (ins->sreg1 != mips_at)
-                                       mips_move (code, mips_at, ins->sreg1);
+                                       MIPS_MOVE (code, mips_at, ins->sreg1);
                                if (ins->sreg2 != mips_v0)
-                                       mips_move (code, mips_v0, ins->sreg2);
-                               mips_move (code, mips_v1, mips_at);
+                                       MIPS_MOVE (code, mips_v0, ins->sreg2);
+                               MIPS_MOVE (code, mips_v1, mips_at);
                        }
                        else {
                                if (ins->sreg2 != mips_v0)
-                                       mips_move (code, mips_v0, ins->sreg2);
+                                       MIPS_MOVE (code, mips_v0, ins->sreg2);
                                if (ins->sreg1 != mips_v1)
-                                       mips_move (code, mips_v1, ins->sreg1);
+                                       MIPS_MOVE (code, mips_v1, ins->sreg1);
                        }
                        break;
                case OP_FMOVE:
@@ -3371,11 +3621,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_cvtsd (code, ins->dreg, ins->sreg1);
                        break;
                case OP_FCONV_TO_R4:
-                       /* Convert from double to float */
-                       mips_cvtsd (code, ins->dreg, ins->sreg1);
 #if 0
-                       /* and back again */
-                       mips_cvtds (code, ins->dreg, ins->dreg);
+                       mips_cvtsd (code, ins->dreg, ins->sreg1);
+#else
+                       /* Just a move, no precision change */
+                       if (ins->dreg != ins->sreg1) {
+                               mips_fmovd (code, ins->dreg, ins->sreg1);
+                       }
 #endif
                        break;
                case OP_JMP:
@@ -3452,7 +3704,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        case OP_VCALL2_REG:
                        case OP_VOIDCALL_REG:
                        case OP_CALL_REG:
-                               mips_move (code, mips_t9, ins->sreg1);
+                               MIPS_MOVE (code, mips_t9, ins->sreg1);
                                break;
                        case OP_FCALL_MEMBASE:
                        case OP_LCALL_MEMBASE:
@@ -3479,16 +3731,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* Round up ins->sreg1, mips_at ends up holding size */
                        mips_addiu (code, mips_at, ins->sreg1, 31);
-                       mips_andi (code, mips_at, mips_at, ~31);
+                       mips_addiu (code, mips_temp, mips_zero, ~31);
+                       mips_and (code, mips_at, mips_at, mips_temp);
 
                        mips_subu (code, mips_sp, mips_sp, mips_at);
+                       g_assert (mips_is_imm16 (area_offset));
                        mips_addiu (code, ins->dreg, mips_sp, area_offset);
 
                        if (ins->flags & MONO_INST_INIT) {
                                mips_move (code, mips_temp, ins->dreg);
                                mips_sb (code, mips_zero, mips_temp, 0);
                                mips_addiu (code, mips_at, mips_at, -1);
-                               mips_bne (code, mips_at, mips_zero, -4);
+                               mips_bne (code, mips_at, mips_zero, -3);
                                mips_addiu (code, mips_temp, mips_temp, 1);
                        }
                        break;
@@ -3540,7 +3794,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        code = emit_unreserve_param_area (cfg, code);
 
                        if (ins->sreg1 != mips_v0)
-                               mips_move (code, mips_v0, ins->sreg1);
+                               MIPS_MOVE (code, mips_v0, ins->sreg1);
                        if (mips_is_imm16 (spvar->inst_offset)) {
                                mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
                        } else {
@@ -3604,13 +3858,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert (ins->sreg1 != -1);
                        mips_sll (code, mips_at, ins->sreg1, 2);
                        if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
-                               mips_move (code, mips_t8, mips_ra);
+                               MIPS_MOVE (code, mips_t8, mips_ra);
                        mips_bgezal (code, mips_zero, 1);       /* bal */
                        mips_nop (code);
                        mips_addu (code, mips_t9, mips_ra, mips_at);
                        /* Table is 16 or 20 bytes from target of bal above */
                        if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
-                               mips_move (code, mips_ra, mips_t8);
+                               MIPS_MOVE (code, mips_ra, mips_t8);
                                mips_lw (code, mips_t9, mips_t9, 20);
                        }
                        else
@@ -3626,7 +3880,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_beq (code, mips_at, mips_zero, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
                case OP_CLT:
                case OP_CLT_UN:
@@ -3635,7 +3889,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_bltz (code, mips_at, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
                case OP_CGT:
                case OP_CGT_UN:
@@ -3644,7 +3898,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_bgtz (code, mips_at, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
 
                case OP_MIPS_COND_EXC_EQ:
@@ -3716,6 +3970,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mips_nop (code);
                                break;
 
+                       case OP_MIPS_COND_EXC_GT_UN:
+                               mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
+                               throw = (guint32 *)(void *)code;
+                               mips_bne (code, mips_at, mips_zero, 0);
+                               mips_nop (code);
+                               break;
+
                        case OP_MIPS_COND_EXC_LT:
                                mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
                                throw = (guint32 *)(void *)code;
@@ -3723,6 +3984,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mips_nop (code);
                                break;
 
+                       case OP_MIPS_COND_EXC_LT_UN:
+                               mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
+                               throw = (guint32 *)(void *)code;
+                               mips_bne (code, mips_at, mips_zero, 0);
+                               mips_nop (code);
+                               break;
+
                        default:
                                /* Not yet implemented */
                                g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
@@ -3748,11 +4016,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                /* floating point opcodes */
                case OP_R8CONST:
+#if 0
                        if (((guint32)ins->inst_p0) & (1 << 15))
                                mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
                        else
                                mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
                        mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
+#else
+                       mips_load_const (code, mips_at, ins->inst_p0);
+                       mips_lwc1 (code, ins->dreg, mips_at, 4);
+                       mips_lwc1 (code, ins->dreg+1, mips_at, 0);
+#endif
                        break;
                case OP_R4CONST:
                        if (((guint32)ins->inst_p0) & (1 << 15))
@@ -3766,11 +4040,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_STORER8_MEMBASE_REG:
                        if (mips_is_imm16 (ins->inst_offset)) {
-#if 1
-                               mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
                                mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
                                mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+                               mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
 #endif
                        } else {
                                mips_load_const (code, mips_at, ins->inst_offset);
@@ -3781,11 +4055,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_LOADR8_MEMBASE:
                        if (mips_is_imm16 (ins->inst_offset)) {
-#if 1
-                               mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
                                mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
                                mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+                               mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
 #endif
                        } else {
                                mips_load_const (code, mips_at, ins->inst_offset);
@@ -3795,35 +4069,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        break;
                case OP_STORER4_MEMBASE_REG:
+                       g_assert (mips_is_imm16 (ins->inst_offset));
 #if PROMOTE_R4_TO_R8
                        /* Need to convert ins->sreg1 to single-precision first */
                        mips_cvtsd (code, mips_ftemp, ins->sreg1);
 #endif
-                       if (mips_is_imm16 (ins->inst_offset)) {
-                               mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
-                       } else {
-                               mips_load_const (code, mips_at, ins->inst_offset);
-                               mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
-                               mips_swc1 (code, mips_ftemp, mips_at, 0);
-                       }
+                       mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
                        break;
                case OP_MIPS_LWC1:
-                       if (mips_is_imm16 (ins->inst_offset)) {
-                               mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
-                       } else {
-                               mips_load_const (code, mips_at, ins->inst_offset);
-                               mips_addu (code, mips_at, mips_at, ins->inst_basereg);
-                               mips_lwc1 (code, ins->dreg, mips_at, 0);
-                       }
+                       g_assert (mips_is_imm16 (ins->inst_offset));
+                       mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
                        break;
                case OP_LOADR4_MEMBASE:
-                       if (mips_is_imm16 (ins->inst_offset)) {
-                               mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
-                       } else {
-                               mips_load_const (code, mips_at, ins->inst_offset);
-                               mips_addu (code, mips_at, mips_at, ins->inst_basereg);
-                               mips_lwc1 (code, ins->dreg, mips_at, 0);
-                       }
+                       g_assert (mips_is_imm16 (ins->inst_offset));
+                       mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
 #if PROMOTE_R4_TO_R8
                        /* Convert to double precision in place */
                        mips_cvtds (code, ins->dreg, ins->dreg);
@@ -3872,19 +4131,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_FCONV_TO_U:
                        code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
                        break;
-               case OP_FCONV_TO_I8:
-               case OP_FCONV_TO_U8:
-                       g_assert_not_reached ();
-                       /* Implemented as helper calls */
-                       break;
-               case OP_LCONV_TO_R_UN:
-                       g_assert_not_reached ();
-                       /* Implemented as helper calls */
-                       break;
-               case OP_LCONV_TO_OVF_I:
-                       g_assert_not_reached ();
-                       /* split up by brg file */
-                       break;
                case OP_SQRT:
                        mips_fsqrtd (code, ins->dreg, ins->sreg1);
                        break;
@@ -3903,26 +4149,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_FNEG:
                        mips_fnegd (code, ins->dreg, ins->sreg1);
                        break;          
-               case OP_FREM:
-                       /* emulated */
-                       g_assert_not_reached ();
-                       break;
-               case OP_FCOMPARE:
-                       g_assert_not_reached();
-                       break;
                case OP_FCEQ:
                        mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_fbtrue (code, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
                case OP_FCLT:
                        mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_fbtrue (code, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
                case OP_FCLT_UN:
                        /* Less than, or Unordered */
@@ -3930,11 +4169,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_addiu (code, ins->dreg, mips_zero, 1);
                        mips_fbtrue (code, 2);
                        mips_nop (code);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        break;
                case OP_FCGT:
                        mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        mips_fbtrue (code, 2);
                        mips_nop (code);
                        mips_addiu (code, ins->dreg, mips_zero, 1);
@@ -3942,7 +4181,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_FCGT_UN:
                        /* Greater than, or Unordered */
                        mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
-                       mips_move (code, ins->dreg, mips_zero);
+                       MIPS_MOVE (code, ins->dreg, mips_zero);
                        mips_fbtrue (code, 2);
                        mips_nop (code);
                        mips_addiu (code, ins->dreg, mips_zero, 1);
@@ -3977,7 +4216,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_fbtrue (code, 0);
                        mips_nop (code);
                        break;
-               case OP_FBLT_UN:
+               case OP_MIPS_FBLT_UN:
                        mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
                        mips_nop (code);
                        if (ins->flags & MONO_INST_BRLABEL)
@@ -4048,19 +4287,24 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        mips_nop (code);
                        break;
                case OP_CKFINITE: {
-                       g_assert_not_reached();
-#if 0
-                       ppc_stfd (code, ins->sreg1, -8, ppc_sp);
-                       ppc_lwz (code, ppc_r11, -8, ppc_sp);
-                       ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
-                       ppc_addis (code, ppc_r11, ppc_r11, -32752);
-                       ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
-                       EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
-#endif
+                       guint32 *branch_patch;
+
+                       mips_mfc1 (code, mips_at, ins->sreg1+1);
+                       mips_srl (code, mips_at, mips_at, 16+4);
+                       mips_andi (code, mips_at, mips_at, 2047);
+                       mips_addiu (code, mips_at, mips_at, -2047);
+
+                       branch_patch = (guint32 *)(void *)code;
+                       mips_bne (code, mips_at, mips_zero, 0);
+                       mips_nop (code);
+
+                       EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
+                       mips_patch (branch_patch, (guint32)code);
+                       mips_fmovd (code, ins->dreg, ins->sreg1);
                        break;
                }
                case OP_JUMP_TABLE:
-                       mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+                       mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
                        mips_load (code, ins->dreg, 0x0f0f0f0f);
                        break;
 
@@ -4097,9 +4341,7 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
 
        for (patch_info = ji; patch_info; patch_info = patch_info->next) {
                unsigned char *ip = patch_info->ip.i + code;
-               const unsigned char *target;
-
-               target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+               const unsigned char *target = NULL;
 
                switch (patch_info->type) {
                case MONO_PATCH_INFO_IP:
@@ -4129,6 +4371,7 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
                case MONO_PATCH_INFO_R4:
                case MONO_PATCH_INFO_R8:
                        /* from OP_AOTCONST : lui + addiu */
+                       target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
                        patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
                        continue;
 #if 0
@@ -4141,12 +4384,14 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
                        /* everything is dealt with at epilog output time */
                        continue;
                default:
+                       target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+                       mips_patch ((guint32 *)(void *)ip, (guint32)target);
                        break;
                }
-               mips_patch ((guint32 *)(void *)ip, (guint32)target);
        }
 }
 
+#if 0
 static
 void
 mono_trace_lmf_prolog (MonoLMF *new_lmf)
@@ -4158,6 +4403,7 @@ void
 mono_trace_lmf_epilog (MonoLMF *old_lmf)
 {
 }
+#endif
 
 /*
  * Allow tracing to work with this interface (with an optional argument)
@@ -4171,55 +4417,43 @@ void*
 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
 {
        guchar *code = p;
-       int fp_stack_offset = 0;
+       int offset = cfg->arch.tracing_offset;
 
        mips_nop (code);
        mips_nop (code);
        mips_nop (code);
 
-       mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
-       mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
-       mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
-       mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
-#if 0
-#if 0
-       fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
-       mips_addiu (code, mips_sp, mips_sp, -64);
-       mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
-       mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
-       mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
-       mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
-#else
-       mips_fmovs (code, mips_f22, mips_f12);
-       mips_fmovs (code, mips_f23, mips_f13);
-       mips_fmovs (code, mips_f24, mips_f14);
-       mips_fmovs (code, mips_f25, mips_f15);
-#endif
+       /* For N32, need to know for each stack slot if it's an integer
+        * or float argument, and save/restore the appropriate register
+        */
+       MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
+#if _MIPS_SIM == _ABIN32
+       MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
+       MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
 #endif
+
        mips_load_const (code, mips_a0, cfg->method);
-       mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
+       mips_addiu (code, mips_a1, mips_sp, offset);
        mips_load_const (code, mips_t9, func);
        mips_jalr (code, mips_t9, mips_ra);
        mips_nop (code);
 
-       mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
-       mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
-       mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
-       mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
-#if 0
-#if 0
-       mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
-       mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
-       mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
-       mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
-       mips_addiu (code, mips_sp, mips_sp, 64);
-#else
-       mips_fmovs (code, mips_f12, mips_f22);
-       mips_fmovs (code, mips_f13, mips_f23);
-       mips_fmovs (code, mips_f14, mips_f24);
-       mips_fmovs (code, mips_f15, mips_f25);
-#endif
+       MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
+#if _MIPS_SIM == _ABIN32
+       MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
+       MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
 #endif
+
        mips_nop (code);
        mips_nop (code);
        mips_nop (code);
@@ -4238,7 +4472,7 @@ mips_adjust_stackframe(MonoCompile *cfg)
                return;
 
        /* adjust cfg->stack_offset for account for down-spilling */
-       cfg->stack_offset += 4;
+       cfg->stack_offset += SIZEOF_REGISTER;
 
        /* re-align cfg->stack_offset if needed (due to var spilling) */
        cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
@@ -4248,7 +4482,7 @@ mips_adjust_stackframe(MonoCompile *cfg)
                g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
        }
        threshold = cfg->arch.local_alloc_offset;
-       ra_offset = cfg->stack_offset - 4;
+       ra_offset = cfg->stack_offset - sizeof(gpointer);
        if (cfg->verbose_level > 2) {
                g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
        }
@@ -4286,10 +4520,24 @@ mips_adjust_stackframe(MonoCompile *cfg)
                        g_print ("BASIC BLOCK %d:\n", bb->block_num);
                }
                MONO_BB_FOR_EACH_INS (bb, ins) {
+                       int adj_c0 = 0;
+                       int adj_imm = 0;
+
                        if (cfg->verbose_level > 2) {
                                mono_print_ins_index (ins_cnt, ins);
                        }
-                       if ((MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp)) || (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))) {
+                       if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
+                               adj_c0 = 1;
+                       if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
+                               adj_c0 = 1;
+                       /* The following two catch FP spills */
+                       if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
+                               adj_c0 = 1;
+                       if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
+                               adj_c0 = 1;
+                       if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
+                               adj_imm = 1;
+                       if (adj_c0) {
                                if (ins->inst_c0 >= threshold) {
                                        ins->inst_c0 += delta;
                                        if (cfg->verbose_level > 2) {
@@ -4306,6 +4554,17 @@ mips_adjust_stackframe(MonoCompile *cfg)
                                }
                                g_assert (ins->inst_c0 != ra_offset);
                        }
+                       if (adj_imm) {
+                               if (ins->inst_imm >= threshold) {
+                                       ins->inst_imm += delta;
+                                       if (cfg->verbose_level > 2) {
+                                               g_print ("adj");
+                                               mono_print_ins_index (ins_cnt, ins);
+                                       }
+                               }
+                               g_assert (ins->inst_c0 != ra_offset);
+                       }
+
                        ++ins_cnt;
                }
        }
@@ -4365,6 +4624,16 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        cfg->code_size = 768 + sig->param_count * 20;
        code = cfg->native_code = g_malloc (cfg->code_size);
 
+       if (tracing) {
+#if _MIPS_SIM == _ABIO32
+               cfg->arch.tracing_offset = cfg->stack_offset;
+#elif _MIPS_SIM == _ABIN32
+               /* no stack slots by default for argument regs, reserve a special block */
+               cfg->arch.tracing_offset = cfg->stack_offset;
+               cfg->stack_offset += 8 * SIZEOF_REGISTER;
+#endif
+       }
+
        /* adjust stackframe assignments for spillvars if needed */
        mips_adjust_stackframe (cfg);
 
@@ -4404,16 +4673,16 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                pos = cfg->arch.iregs_offset;
                for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
                        if (iregs_to_save & (1 << i)) {
-                               g_assert (pos < cfg->stack_usage - 4);
-                               mips_sw (code, i, mips_sp, pos);
-                               pos += sizeof (gulong);
+                               g_assert (pos < cfg->stack_usage - sizeof(gpointer));
+                               MIPS_SW (code, i, mips_sp, pos);
+                               pos += SIZEOF_REGISTER;
                        }
                }
        }
 #if SAVE_LMF
        if (method->save_lmf) {
                for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
-                       mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
+                       MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
                }
        }
 #endif
@@ -4438,10 +4707,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 #endif
 #endif
        if (cfg->frame_reg != mips_sp) {
-               mips_move (code, cfg->frame_reg, mips_sp);
+               MIPS_MOVE (code, cfg->frame_reg, mips_sp);
 #if SAVE_LMF
                if (method->save_lmf)
-                       mips_sw (code, cfg->frame_reg, mips_sp,
+                       MIPS_SW (code, cfg->frame_reg, mips_sp,
                                 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
 #endif
        }
@@ -4449,8 +4718,9 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        /* Do instrumentation before assigning regvars to registers.  Because they may be assigned
         * to the t* registers, which would be clobbered by the instrumentation calls.
         */
-       if (tracing)
+       if (tracing) {
                code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
+       }
 
 
        /* load arguments allocated to register from the stack */
@@ -4462,7 +4732,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                ArgInfo *ainfo = &cinfo->ret;
                inst = cfg->vret_addr;
                if (inst->opcode == OP_REGVAR)
-                       mips_move (code, inst->dreg, ainfo->reg);
+                       MIPS_MOVE (code, inst->dreg, ainfo->reg);
                else if (mips_is_imm16 (inst->inst_offset)) {
                        mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
                } else {
@@ -4481,7 +4751,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                if (inst->opcode == OP_REGVAR) {
                        /* Argument ends up in a register */
                        if (ainfo->regtype == RegTypeGeneral)
-                               mips_move (code, inst->dreg, ainfo->reg);
+                               MIPS_MOVE (code, inst->dreg, ainfo->reg);
                        else if (ainfo->regtype == RegTypeFP) {
                                g_assert_not_reached();
 #if 0
@@ -4515,8 +4785,12 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
                                        break;
                                case 8:
+#if (SIZEOF_REGISTER == 4)
                                        mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
                                        mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
+#elif (SIZEOF_REGISTER == 8)
+                                       mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+#endif
                                        break;
                                default:
                                        g_assert_not_reached ();
@@ -4548,11 +4822,11 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        } else if (ainfo->regtype == RegTypeFP) {
                                g_assert (mips_is_imm16 (inst->inst_offset));
                                if (ainfo->size == 8) {
-#if 1
-                                       mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
                                        mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
                                        mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+                                       mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
 #endif
                                }
                                else if (ainfo->size == 4)
@@ -4567,8 +4841,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
                                /* Push the argument registers into their stack slots */
                                for (i = 0; i < ainfo->size; ++i) {
-                                       mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
-                                       doffset += sizeof (gpointer);
+                                       MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
+                                       doffset += SIZEOF_REGISTER;
                                }
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
                                g_assert (mips_is_imm16 (inst->inst_offset));
@@ -4624,7 +4898,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /* save method info */
                mips_load_const (code, mips_at, method);
                mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
-               mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
+               MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
 
                /* save the current IP */
                mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
@@ -4677,10 +4951,6 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
                else
                        save_mode = SAVE_NONE;
                break;
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-               save_mode = SAVE_TWO;
-               break;
        case MONO_TYPE_R4:
        case MONO_TYPE_R8:
                save_mode = SAVE_FP;
@@ -4688,6 +4958,14 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
        case MONO_TYPE_VALUETYPE:
                save_mode = SAVE_STRUCT;
                break;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+#if SIZEOF_REGISTER == 4
+               save_mode = SAVE_TWO;
+#elif SIZEOF_REGISTER == 8
+               save_mode = SAVE_ONE;
+#endif
+               break;
        default:
                save_mode = SAVE_ONE;
                break;
@@ -4697,23 +4975,23 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
        switch (save_mode) {
        case SAVE_TWO:
                mips_sw (code, mips_v0, mips_sp, save_offset);
-               mips_sw (code, mips_v1, mips_sp, save_offset + 4);
+               mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
                if (enable_arguments) {
-                       mips_move (code, mips_a1, mips_v0);
-                       mips_move (code, mips_a2, mips_v1);
+                       MIPS_MOVE (code, mips_a1, mips_v0);
+                       MIPS_MOVE (code, mips_a2, mips_v1);
                }
                break;
        case SAVE_ONE:
-               mips_sw (code, mips_v0, mips_sp, save_offset);
+               MIPS_SW (code, mips_v0, mips_sp, save_offset);
                if (enable_arguments) {
-                       mips_move (code, mips_a1, mips_v0);
+                       MIPS_MOVE (code, mips_a1, mips_v0);
                }
                break;
        case SAVE_FP:
                mips_sdc1 (code, mips_f0, mips_sp, save_offset);
                mips_ldc1 (code, mips_f12, mips_sp, save_offset);
                mips_lw (code, mips_a0, mips_sp, save_offset);
-               mips_lw (code, mips_a1, mips_sp, save_offset+4);
+               mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
                break;
        case SAVE_STRUCT:
        case SAVE_NONE:
@@ -4728,10 +5006,10 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
        switch (save_mode) {
        case SAVE_TWO:
                mips_lw (code, mips_v0, mips_sp, save_offset);
-               mips_lw (code, mips_v1, mips_sp, save_offset + 4);
+               mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
                break;
        case SAVE_ONE:
-               mips_lw (code, mips_v0, mips_sp, save_offset);
+               MIPS_LW (code, mips_v0, mips_sp, save_offset);
                break;
        case SAVE_FP:
                mips_ldc1 (code, mips_f0, mips_sp, save_offset);
@@ -4751,7 +5029,7 @@ guint8 *
 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
 {
        MonoMethod *method = cfg->method;
-       int pos, i;
+       int pos = 0, i;
        int max_epilog_size = 16 + 20*4;
        guint32 iregs_to_restore;
 #if SAVE_FP_REGS
@@ -4790,7 +5068,7 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
        }
        pos = cfg->arch.iregs_offset;
        if (cfg->frame_reg != mips_sp) {
-               mips_move (code, mips_sp, cfg->frame_reg);
+               MIPS_MOVE (code, mips_sp, cfg->frame_reg);
        }
 #if SAVE_ALL_REGS
        iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
@@ -4800,8 +5078,8 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
        if (iregs_to_restore) {
                for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
                        if (iregs_to_restore & (1 << i)) {
-                               mips_lw (code, i, mips_sp, pos);
-                               pos += sizeof (gulong);
+                               MIPS_LW (code, i, mips_sp, pos);
+                               pos += SIZEOF_REGISTER;
                        }
                }
        }
@@ -4818,7 +5096,7 @@ mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
                        if (fregs_to_restore & (1 << i)) {
                                g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
                                mips_lwc1 (code, i, mips_sp, pos);
-                               pos += sizeof (gulong);
+                               pos += FREG_SIZE
                        }
                }
        }
@@ -4869,6 +5147,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
 }
 
 /* remove once throw_exception_by_name is eliminated */
+#if 0
 static int
 exception_id_by_name (const char *name)
 {
@@ -4889,6 +5168,7 @@ exception_id_by_name (const char *name)
        g_error ("Unknown intrinsic exception %s\n", name);
        return 0;
 }
+#endif
 
 void
 mono_arch_emit_exceptions (MonoCompile *cfg)
@@ -5247,7 +5527,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        } else {
                /* the initial load of the vtable address */
                size += 8;
-               code = mono_code_manager_reserve (domain->code_mp, size);
+               code = mono_domain_code_reserve (domain, size);
        }
        start = code;
        if (!fail_tramp)