Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[mono.git] / mono / mini / mini-arm.c
index d9bb03581e72b898802d68b16e14a2f1d2853518..96fe2249c56fe4ac3f2656b9921adc689ab18171 100644 (file)
@@ -31,8 +31,6 @@ static CRITICAL_SECTION mini_arch_mutex;
 static int v5_supported = 0;
 static int thumb_supported = 0;
 
-static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount);
-
 /*
  * TODO:
  * floating point support: on ARM it is a mess, there are at least 3
@@ -43,7 +41,7 @@ static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount);
  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
  * 3) VFP: the new and actually sensible and useful FP support. Implemented
- *    in HW or kernel-emulated, requires new tools. I think this ios what symbian uses.
+ *    in HW or kernel-emulated, requires new tools. I think this is what symbian uses.
  *
  * The plan is to write the FPA support first. softfloat can be tested in a chroot.
  */
@@ -61,8 +59,11 @@ int mono_exc_esp_offset = 0;
 #define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) |  (ARMREG_LR << 12) | ARMREG_PC)
 #define DEBUG_IMT 0
 
+void mini_emit_memcpy2 (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align);
+
 const char*
-mono_arch_regname (int reg) {
+mono_arch_regname (int reg)
+{
        static const char * rnames[] = {
                "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
                "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
@@ -75,7 +76,8 @@ mono_arch_regname (int reg) {
 }
 
 const char*
-mono_arch_fregname (int reg) {
+mono_arch_fregname (int reg)
+{
        static const char * rnames[] = {
                "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
                "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
@@ -177,6 +179,23 @@ emit_call_seq (MonoCompile *cfg, guint8 *code)
        return code;
 }
 
+static guint8*
+emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
+{
+       switch (ins->opcode) {
+       case OP_FCALL:
+       case OP_FCALL_REG:
+       case OP_FCALL_MEMBASE:
+#ifdef ARM_FPU_FPA
+               if (ins->dreg != ARM_FPA_F0)
+                       ARM_MVFD (code, ins->dreg, ARM_FPA_F0);
+#endif
+               break;
+       }
+
+       return code;
+}
+
 /*
  * mono_arch_get_argument_info:
  * @csig:  a method signature
@@ -192,7 +211,7 @@ int
 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
 {
        int k, frame_size = 0;
-       int size, align, pad;
+       guint32 size, align, pad;
        int offset = 8;
 
        if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
@@ -210,11 +229,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        arg_info [0].size = frame_size;
 
        for (k = 0; k < param_count; k++) {
-               
-               if (csig->pinvoke)
-                       size = mono_type_native_stack_size (csig->params [k], &align);
-               else
-                       size = mini_type_stack_size (NULL, csig->params [k], &align);
+               size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
 
                /* ignore alignment for now */
                align = 1;
@@ -397,7 +412,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 }
 
 gpointer
-mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
 {
        /* FIXME: handle returning a struct */
        if (MONO_TYPE_ISSTRUCT (sig->ret))
@@ -437,6 +452,10 @@ guint32
 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
 {
        guint32 opts = 0;
+#if __APPLE__
+       thumb_supported = TRUE;
+       v5_supported = TRUE;
+#else
        char buf [512];
        char *line;
        FILE *file = fopen ("/proc/cpuinfo", "r");
@@ -462,6 +481,7 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
                fclose (file);
                /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
        }
+#endif
 
        /* no arm-specific optimizations yet */
        *exclude_mask = 0;
@@ -472,7 +492,7 @@ static gboolean
 is_regsize_var (MonoType *t) {
        if (t->byref)
                return TRUE;
-       t = mono_type_get_underlying_type (t);
+       t = mini_type_get_underlying_type (NULL, t);
        switch (t->type) {
        case MONO_TYPE_I4:
        case MONO_TYPE_U4:
@@ -535,7 +555,9 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
        regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
        regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
        regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
-       regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
+       if (!(cfg->compile_aot || cfg->uses_rgctx_reg))
+               /* V5 is reserved for passing the vtable/rgctx/IMT method */
+               regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
        /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
        /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
 
@@ -559,6 +581,9 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
 void
 mono_arch_flush_icache (guint8 *code, gint size)
 {
+#if __APPLE__
+       sys_icache_invalidate (code, size);
+#else
        __asm __volatile ("mov r0, %0\n"
                        "mov r1, %1\n"
                        "mov r2, %2\n"
@@ -566,7 +591,7 @@ mono_arch_flush_icache (guint8 *code, gint size)
                        : /* no outputs */
                        : "r" (code), "r" (code + size), "r" (0)
                        : "r0", "r1", "r3" );
-
+#endif
 }
 
 enum {
@@ -646,7 +671,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
 {
        guint i, gr;
        int n = sig->hasthis + sig->param_count;
-       guint32 simpletype;
+       MonoType *simpletype;
        guint32 stack_size = 0;
        CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
 
@@ -679,8 +704,8 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                        n++;
                        continue;
                }
-               simpletype = mono_type_get_underlying_type (sig->params [i])->type;
-               switch (simpletype) {
+               simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
+               switch (simpletype->type) {
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -729,7 +754,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                        int align_size;
                        int nwords;
 
-                       if (simpletype == MONO_TYPE_TYPEDBYREF) {
+                       if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
                                size = sizeof (MonoTypedRef);
                        } else {
                                MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
@@ -777,8 +802,8 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
        }
 
        {
-               simpletype = mono_type_get_underlying_type (sig->ret)->type;
-               switch (simpletype) {
+               simpletype = mini_type_get_underlying_type (NULL, sig->ret);
+               switch (simpletype->type) {
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -838,7 +863,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
  * The locals var stuff should most likely be split in another method.
  */
 void
-mono_arch_allocate_vars (MonoCompile *m)
+mono_arch_allocate_vars (MonoCompile *cfg)
 {
        MonoMethodSignature *sig;
        MonoMethodHeader *header;
@@ -847,13 +872,13 @@ mono_arch_allocate_vars (MonoCompile *m)
        int frame_reg = ARMREG_FP;
 
        /* FIXME: this will change when we use FP as gcc does */
-       m->flags |= MONO_CFG_HAS_SPILLUP;
+       cfg->flags |= MONO_CFG_HAS_SPILLUP;
 
        /* allow room for the vararg method args: void* and long/double */
-       if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
-               m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
+       if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
+               cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
 
-       header = mono_method_get_header (m->method);
+       header = mono_method_get_header (cfg->method);
 
        /* 
         * We use the frame register also for any method that has
@@ -864,28 +889,29 @@ mono_arch_allocate_vars (MonoCompile *m)
         * filters get called before stack unwinding happens) when the filter
         * code would call any method (this also applies to finally etc.).
         */ 
-       if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
+       if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
                frame_reg = ARMREG_FP;
-       m->frame_reg = frame_reg;
+       cfg->frame_reg = frame_reg;
        if (frame_reg != ARMREG_SP) {
-               m->used_int_regs |= 1 << frame_reg;
+               cfg->used_int_regs |= 1 << frame_reg;
        }
 
-       sig = mono_method_signature (m->method);
+       if (!cfg->compile_aot || cfg->uses_rgctx_reg)
+               /* V5 is reserved for passing the vtable/rgctx/IMT method */
+               cfg->used_int_regs |= (1 << ARMREG_V5);
+
+       sig = mono_method_signature (cfg->method);
        
        offset = 0;
        curinst = 0;
-       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               m->ret->opcode = OP_REGVAR;
-               m->ret->inst_c0 = ARMREG_R0;
-       } else {
+       if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
                /* FIXME: handle long and FP values */
-               switch (mono_type_get_underlying_type (sig->ret)->type) {
+               switch (mini_type_get_underlying_type (NULL, sig->ret)->type) {
                case MONO_TYPE_VOID:
                        break;
                default:
-                       m->ret->opcode = OP_REGVAR;
-                       m->ret->inst_c0 = ARMREG_R0;
+                       cfg->ret->opcode = OP_REGVAR;
+                       cfg->ret->inst_c0 = ARMREG_R0;
                        break;
                }
        }
@@ -900,44 +926,51 @@ mono_arch_allocate_vars (MonoCompile *m)
        //offset &= ~(8 - 1);
 
        /* add parameter area size for called functions */
-       offset += m->param_area;
+       offset += cfg->param_area;
        offset += 8 - 1;
        offset &= ~(8 - 1);
-       if (m->flags & MONO_CFG_HAS_FPOUT)
+       if (cfg->flags & MONO_CFG_HAS_FPOUT)
                offset += 8;
 
        /* allow room to save the return value */
-       if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
+       if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
                offset += 8;
 
        /* the MonoLMF structure is stored just below the stack pointer */
 
        if (sig->call_convention == MONO_CALL_VARARG) {
-                m->sig_cookie = 0;
+                cfg->sig_cookie = 0;
         }
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               inst = m->ret;
+               inst = cfg->vret_addr;
                offset += sizeof(gpointer) - 1;
                offset &= ~(sizeof(gpointer) - 1);
                inst->inst_offset = offset;
                inst->opcode = OP_REGOFFSET;
                inst->inst_basereg = frame_reg;
+               if (G_UNLIKELY (cfg->verbose_level > 1)) {
+                       printf ("vret_addr =");
+                       mono_print_ins (cfg->vret_addr);
+               }
                offset += sizeof(gpointer);
                if (sig->call_convention == MONO_CALL_VARARG)
-                       m->sig_cookie += sizeof (gpointer);
+                       cfg->sig_cookie += sizeof (gpointer);
        }
 
-       curinst = m->locals_start;
-       for (i = curinst; i < m->num_varinfo; ++i) {
-               inst = m->varinfo [i];
+       curinst = cfg->locals_start;
+       for (i = curinst; i < cfg->num_varinfo; ++i) {
+               inst = cfg->varinfo [i];
                if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
                        continue;
 
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structure */
-               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
-                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
+                       guint32 ualign;
+                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &ualign);
+                       align = ualign;
+               }
                else
                        size = mono_type_size (inst->inst_vtype, &align);
 
@@ -957,7 +990,7 @@ mono_arch_allocate_vars (MonoCompile *m)
 
        curinst = 0;
        if (sig->hasthis) {
-               inst = m->args [curinst];
+               inst = cfg->args [curinst];
                if (inst->opcode != OP_REGVAR) {
                        inst->opcode = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
@@ -966,13 +999,13 @@ mono_arch_allocate_vars (MonoCompile *m)
                        inst->inst_offset = offset;
                        offset += sizeof (gpointer);
                        if (sig->call_convention == MONO_CALL_VARARG)
-                               m->sig_cookie += sizeof (gpointer);
+                               cfg->sig_cookie += sizeof (gpointer);
                }
                curinst++;
        }
 
        for (i = 0; i < sig->param_count; ++i) {
-               inst = m->args [curinst];
+               inst = cfg->args [curinst];
                if (inst->opcode != OP_REGVAR) {
                        inst->opcode = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
@@ -987,7 +1020,7 @@ mono_arch_allocate_vars (MonoCompile *m)
                        inst->inst_offset = offset;
                        offset += size;
                        if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
-                               m->sig_cookie += size;
+                               cfg->sig_cookie += size;
                }
                curinst++;
        }
@@ -997,13 +1030,24 @@ mono_arch_allocate_vars (MonoCompile *m)
        offset &= ~(8 - 1);
 
        /* change sign? */
-       m->stack_offset = offset;
-
+       cfg->stack_offset = offset;
 }
 
-/* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
- * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
- */
+void
+mono_arch_create_vars (MonoCompile *cfg)
+{
+       MonoMethodSignature *sig;
+
+       sig = mono_method_signature (cfg->method);
+
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
+               if (G_UNLIKELY (cfg->verbose_level > 1)) {
+                       printf ("vret_addr = ");
+                       mono_print_ins (cfg->vret_addr);
+               }
+       }
+}
 
 /* 
  * take the arguments and generate the arch-specific
@@ -1039,7 +1083,10 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                        MONO_INST_NEW (cfg, arg, OP_OUTARG);
                        arg->inst_imm = cinfo->sig_cookie.offset;
                        arg->inst_left = sig_arg;
-                       MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+                       
+                       /* prepend, so they get reversed */
+                       arg->next = call->out_args;
+                       call->out_args = arg;
                }
                if (is_virtual && i == 0) {
                        /* the argument will be attached to the call instrucion */
@@ -1052,7 +1099,9 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                        arg->inst_left = in;
                        arg->inst_right = (MonoInst*)call;
                        arg->type = in->type;
-                       MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+                       /* prepend, we'll need to reverse them later */
+                       arg->next = call->out_args;
+                       call->out_args = arg;
                        if (ainfo->regtype == RegTypeGeneral) {
                                arg->backend.reg3 = ainfo->reg;
                                call->used_iregs |= 1 << ainfo->reg;
@@ -1108,6 +1157,19 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                        }
                }
        }
+       /*
+        * Reverse the call->out_args list.
+        */
+       {
+               MonoInst *prev = NULL, *list = call->out_args, *next;
+               while (list) {
+                       next = list->next;
+                       list->next = prev;
+                       prev = list;
+                       list = next;
+               }
+               call->out_args = prev;
+       }
        call->stack_usage = cinfo->stack_usage;
        cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
        cfg->flags |= MONO_CFG_HAS_CALLS;
@@ -1120,6 +1182,268 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
        return call;
 }
 
+void
+mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
+{
+       MonoInst *in, *ins;
+       MonoMethodSignature *sig;
+       int i, n;
+       CallInfo *cinfo;
+
+       sig = call->signature;
+       n = sig->param_count + sig->hasthis;
+       
+       cinfo = calculate_sizes (sig, sig->pinvoke);
+
+       for (i = 0; i < n; ++i) {
+               ArgInfo *ainfo = cinfo->args + i;
+               MonoType *t;
+
+               if (i >= sig->hasthis)
+                       t = sig->params [i - sig->hasthis];
+               else
+                       t = &mono_defaults.int_class->byval_arg;
+               t = mini_type_get_underlying_type (NULL, t);
+
+               if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+                       /* FIXME: */
+                       NOT_IMPLEMENTED;
+               }
+
+               in = call->args [i];
+
+               switch (ainfo->regtype) {
+               case RegTypeGeneral:
+                       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);
+                               ins->sreg1 = in->dreg + 1;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = mono_alloc_ireg (cfg);
+                               ins->sreg1 = in->dreg + 2;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
+                       } else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
+#ifndef MONO_ARCH_SOFT_FLOAT
+                               int creg;
+#endif
+
+                               if (ainfo->size == 4) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+                                       /* mono_emit_call_args () have already done the r8->r4 conversion */
+                                       /* The converted value is in an int vreg */
+                                       MONO_INST_NEW (cfg, ins, OP_MOVE);
+                                       ins->dreg = mono_alloc_ireg (cfg);
+                                       ins->sreg1 = in->dreg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                                       mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+#else
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
+                                       creg = mono_alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
+                                       mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
+#endif
+                               } else {
+#ifdef MONO_ARCH_SOFT_FLOAT
+                                       MONO_INST_NEW (cfg, ins, OP_FGETLOW32);
+                                       ins->dreg = mono_alloc_ireg (cfg);
+                                       ins->sreg1 = in->dreg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                                       mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+
+                                       MONO_INST_NEW (cfg, ins, OP_FGETHIGH32);
+                                       ins->dreg = mono_alloc_ireg (cfg);
+                                       ins->sreg1 = in->dreg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                                       mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
+#else
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
+                                       creg = mono_alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
+                                       mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
+                                       creg = mono_alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8 + 4));
+                                       mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg + 1, FALSE);
+#endif
+                               }
+                               cfg->flags |= MONO_CFG_HAS_FPOUT;
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = mono_alloc_ireg (cfg);
+                               ins->sreg1 = in->dreg;
+                               MONO_ADD_INS (cfg->cbb, ins);
+
+                               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+                       }
+                       break;
+               case RegTypeStructByAddr:
+                       NOT_IMPLEMENTED;
+#if 0
+                       /* FIXME: where si the data allocated? */
+                       arg->backend.reg3 = ainfo->reg;
+                       call->used_iregs |= 1 << ainfo->reg;
+                       g_assert_not_reached ();
+#endif
+                       break;
+               case RegTypeStructByVal:
+                       MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+                       ins->opcode = OP_OUTARG_VT;
+                       ins->sreg1 = in->dreg;
+                       ins->klass = in->klass;
+                       ins->inst_p0 = call;
+                       ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+                       memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       break;
+               case RegTypeBase:
+                       if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
+                       } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
+                               if (t->type == MONO_TYPE_R8) {
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
+                               } else {
+#ifdef MONO_ARCH_SOFT_FLOAT
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
+#else
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
+#endif
+                               }
+                       } else {
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
+                       }
+                       break;
+               case RegTypeBaseGen:
+                       if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = mono_alloc_ireg (cfg);
+                               ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
+                       } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
+                               int creg;
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+                               g_assert_not_reached ();
+#endif
+
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
+                               creg = mono_alloc_ireg (cfg);
+                               mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
+                               creg = mono_alloc_ireg (cfg);
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 4));
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, creg);
+                               cfg->flags |= MONO_CFG_HAS_FPOUT;
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
+               case RegTypeFP: {
+                       /* FIXME: */
+                       NOT_IMPLEMENTED;
+#if 0
+                       arg->backend.reg3 = ainfo->reg;
+                       /* FP args are passed in int regs */
+                       call->used_iregs |= 1 << ainfo->reg;
+                       if (ainfo->size == 8) {
+                               arg->opcode = OP_OUTARG_R8;
+                               call->used_iregs |= 1 << (ainfo->reg + 1);
+                       } else {
+                               arg->opcode = OP_OUTARG_R4;
+                       }
+#endif
+                       cfg->flags |= MONO_CFG_HAS_FPOUT;
+                       break;
+               }
+               default:
+                       g_assert_not_reached ();
+               }
+       }
+
+       if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
+               MonoInst *vtarg;
+
+               MONO_INST_NEW (cfg, vtarg, OP_MOVE);
+               vtarg->sreg1 = call->vret_var->dreg;
+               vtarg->dreg = mono_alloc_preg (cfg);
+               MONO_ADD_INS (cfg->cbb, vtarg);
+
+               mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
+       }
+
+       call->stack_usage = cinfo->stack_usage;
+
+       g_free (cinfo);
+}
+
+void
+mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
+{
+       MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
+       ArgInfo *ainfo = ins->inst_p1;
+       int ovf_size = ainfo->vtsize;
+       int doffset = ainfo->offset;
+       int i, soffset, dreg;
+
+       soffset = 0;
+       for (i = 0; i < ainfo->size; ++i) {
+               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);
+       }
+       //g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
+       if (ovf_size != 0)
+               mini_emit_memcpy2 (cfg, ARMREG_SP, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+}
+
+void
+mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
+{
+       MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
+
+       if (!ret->byref) {
+               if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
+                       MonoInst *ins;
+
+                       MONO_INST_NEW (cfg, ins, OP_SETLRET);
+                       ins->sreg1 = val->dreg + 1;
+                       ins->sreg2 = val->dreg + 2;
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       return;
+               }
+#ifdef MONO_ARCH_SOFT_FLOAT
+               if (ret->type == MONO_TYPE_R8) {
+                       MonoInst *ins;
+
+                       MONO_INST_NEW (cfg, ins, OP_SETFRET);
+                       ins->dreg = cfg->ret->dreg;
+                       ins->sreg1 = val->dreg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       return;
+               }
+               if (ret->type == MONO_TYPE_R4) {
+                       /* Already converted to an int in method_to_ir () */
+                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+                       return;
+               }                       
+#endif
+       }
+
+       /* FIXME: */
+       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+}
+
+gboolean 
+mono_arch_is_inst_imm (gint64 imm)
+{
+       return TRUE;
+}
+
 /*
  * Allow tracing to work with this interface (with an optional argument)
  */
@@ -1151,7 +1475,7 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
        int save_mode = SAVE_NONE;
        int offset;
        MonoMethod *method = cfg->method;
-       int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
+       int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
        int save_offset = cfg->param_area;
        save_offset += 7;
        save_offset &= ~7;
@@ -1286,19 +1610,22 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
 void
 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
 {
-       MonoInst *ins, *n;
-
-       MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
-               MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
+       MonoInst *ins, *n, *last_ins = NULL;
 
+       MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
                switch (ins->opcode) {
                case OP_MUL_IMM: 
+               case OP_IMUL_IMM: 
+                       /* Already done by an arch-independent pass */
+                       if (cfg->new_ir)
+                               break;
+
                        /* remove unnecessary multiplication with 1 */
                        if (ins->inst_imm == 1) {
                                if (ins->dreg != ins->sreg1) {
                                        ins->opcode = OP_MOVE;
                                } else {
-                                       MONO_DEL_INS (ins);
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                }
                        } else {
@@ -1320,7 +1647,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                            ins->inst_basereg == last_ins->inst_destbasereg &&
                            ins->inst_offset == last_ins->inst_offset) {
                                if (ins->dreg == last_ins->sreg1) {
-                                       MONO_DEL_INS (ins);
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                } else {
                                        //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
@@ -1343,7 +1670,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                              ins->inst_offset == last_ins->inst_offset) {
 
                                if (ins->dreg == last_ins->dreg) {
-                                       MONO_DEL_INS (ins);
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                } else {
                                        ins->opcode = OP_MOVE;
@@ -1395,7 +1722,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                         * OP_MOVE reg, reg 
                         */
                        if (ins->dreg == ins->sreg1) {
-                               MONO_DEL_INS (ins);
+                               MONO_DELETE_INS (bb, ins);
                                continue;
                        }
                        /* 
@@ -1405,12 +1732,15 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && last_ins->opcode == OP_MOVE &&
                            ins->sreg1 == last_ins->dreg &&
                            ins->dreg == last_ins->sreg1) {
-                               MONO_DEL_INS (ins);
+                               MONO_DELETE_INS (bb, ins);
                                continue;
                        }
                        break;
                }
+               last_ins = ins;
+               ins = ins->next;
        }
+       bb->last_ins = last_ins;
 }
 
 /* 
@@ -1442,11 +1772,9 @@ branch_cc_table [] = {
        ARMCOND_LO
 };
 
-
-#define NEW_INS(cfg,ins,dest,op) do {                                  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = (op);  \
-               MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
+#define NEW_INS(cfg,dest,op) do {       \
+               MONO_INST_NEW ((cfg), (dest), (op)); \
+        mono_bblock_insert_before_ins (bb, ins, (dest)); \
        } while (0)
 
 static int
@@ -1461,6 +1789,8 @@ map_to_reg_reg_op (int op)
                return OP_IAND;
        case OP_COMPARE_IMM:
                return OP_COMPARE;
+       case OP_ICOMPARE_IMM:
+               return OP_ICOMPARE;
        case OP_ADDCC_IMM:
                return OP_ADDCC;
        case OP_ADC_IMM:
@@ -1519,38 +1849,47 @@ map_to_reg_reg_op (int op)
 void
 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 {
+       MonoInst *ins, *temp, *last_ins = NULL;
        int rot_amount, imm8, low_imm;
-       MonoInst *ins, *temp;
 
        /* setup the virtual reg allocator */
        if (bb->max_vreg > cfg->rs->next_vreg)
                cfg->rs->next_vreg = bb->max_vreg;
 
        MONO_BB_FOR_EACH_INS (bb, ins) {
-               MonoInst *last_ins;
-
 loop_start:
-               last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
                switch (ins->opcode) {
                case OP_ADD_IMM:
                case OP_SUB_IMM:
                case OP_AND_IMM:
                case OP_COMPARE_IMM:
+               case OP_ICOMPARE_IMM:
                case OP_ADDCC_IMM:
                case OP_ADC_IMM:
                case OP_SUBCC_IMM:
                case OP_SBB_IMM:
                case OP_OR_IMM:
                case OP_XOR_IMM:
+               case OP_IADD_IMM:
+               case OP_ISUB_IMM:
+               case OP_IAND_IMM:
+               case OP_IADC_IMM:
+               case OP_ISBB_IMM:
+               case OP_IOR_IMM:
+               case OP_IXOR_IMM:
                        if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
-                               NEW_INS (cfg, ins, temp, OP_ICONST);
+                               NEW_INS (cfg, temp, OP_ICONST);
                                temp->inst_c0 = ins->inst_imm;
                                temp->dreg = mono_regstate_next_int (cfg->rs);
                                ins->sreg2 = temp->dreg;
-                               ins->opcode = map_to_reg_reg_op (ins->opcode);
+                               if (cfg->new_ir)
+                                       ins->opcode = mono_op_imm_to_op (ins->opcode);
+                               else
+                                       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;
@@ -1566,12 +1905,19 @@ loop_start:
                                ins->inst_imm = imm8;
                                break;
                        }
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_imm;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg2 = temp->dreg;
                        ins->opcode = OP_IMUL;
                        break;
+               case OP_LOCALLOC_IMM:
+                       NEW_INS (cfg, temp, OP_ICONST);
+                       temp->inst_c0 = ins->inst_imm;
+                       temp->dreg = mono_regstate_next_int (cfg->rs);
+                       ins->sreg1 = temp->dreg;
+                       ins->opcode = OP_LOCALLOC;
+                       break;
                case OP_LOAD_MEMBASE:
                case OP_LOADI4_MEMBASE:
                case OP_LOADU4_MEMBASE:
@@ -1583,7 +1929,7 @@ loop_start:
                         */
                        if (arm_is_imm12 (ins->inst_offset))
                                break;
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_offset;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg2 = temp->dreg;
@@ -1594,7 +1940,7 @@ loop_start:
                case OP_LOADI1_MEMBASE:
                        if (arm_is_imm8 (ins->inst_offset))
                                break;
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_offset;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg2 = temp->dreg;
@@ -1606,7 +1952,7 @@ loop_start:
                                break;
                        low_imm = ins->inst_offset & 0x1ff;
                        if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
-                               NEW_INS (cfg, ins, temp, OP_ADD_IMM);
+                               NEW_INS (cfg, temp, OP_ADD_IMM);
                                temp->inst_imm = ins->inst_offset & ~0x1ff;
                                temp->sreg1 = ins->inst_basereg;
                                temp->dreg = mono_regstate_next_int (cfg->rs);
@@ -1622,7 +1968,7 @@ loop_start:
                case OP_STOREI1_MEMBASE_REG:
                        if (arm_is_imm12 (ins->inst_offset))
                                break;
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_offset;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg2 = temp->dreg;
@@ -1631,7 +1977,7 @@ loop_start:
                case OP_STOREI2_MEMBASE_REG:
                        if (arm_is_imm8 (ins->inst_offset))
                                break;
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_offset;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg2 = temp->dreg;
@@ -1643,7 +1989,7 @@ loop_start:
                                break;
                        low_imm = ins->inst_offset & 0x1ff;
                        if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
-                               NEW_INS (cfg, ins, temp, OP_ADD_IMM);
+                               NEW_INS (cfg, temp, OP_ADD_IMM);
                                temp->inst_imm = ins->inst_offset & ~0x1ff;
                                temp->sreg1 = ins->inst_destbasereg;
                                temp->dreg = mono_regstate_next_int (cfg->rs);
@@ -1659,15 +2005,53 @@ loop_start:
                case OP_STOREI1_MEMBASE_IMM:
                case OP_STOREI2_MEMBASE_IMM:
                case OP_STOREI4_MEMBASE_IMM:
-                       NEW_INS (cfg, ins, temp, OP_ICONST);
+                       NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_imm;
                        temp->dreg = mono_regstate_next_int (cfg->rs);
                        ins->sreg1 = temp->dreg;
                        ins->opcode = map_to_reg_reg_op (ins->opcode);
+                       last_ins = temp;
                        goto loop_start; /* make it handle the possibly big ins->inst_offset */
+               case OP_FCOMPARE: {
+                       gboolean swap = FALSE;
+                       int reg;
+
+                       /* Some fp compares require swapped operands */
+                       g_assert (ins->next);
+                       switch (ins->next->opcode) {
+                       case OP_FBGT:
+                               ins->next->opcode = OP_FBLT;
+                               swap = TRUE;
+                               break;
+                       case OP_FBGT_UN:
+                               ins->next->opcode = OP_FBLT_UN;
+                               swap = TRUE;
+                               break;
+                       case OP_FBLE:
+                               ins->next->opcode = OP_FBGE;
+                               swap = TRUE;
+                               break;
+                       case OP_FBLE_UN:
+                               ins->next->opcode = OP_FBGE_UN;
+                               swap = TRUE;
+                               break;
+                       default:
+                               break;
+                       }
+                       if (swap) {
+                               reg = ins->sreg1;
+                               ins->sreg1 = ins->sreg2;
+                               ins->sreg2 = reg;
+                       }
+                       break;
+               }
                }
+
+               last_ins = ins;
        }
+       bb->last_ins = last_ins;
        bb->max_vreg = cfg->rs->next_vreg;
+
 }
 
 static guchar*
@@ -1948,7 +2332,7 @@ arm_patch (guchar *code, const guchar *target)
  * to be used with the emit macros.
  * Return -1 otherwise.
  */
-static int
+int
 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
 {
        guint32 res, i;
@@ -2013,6 +2397,128 @@ mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
        return code;
 }
 
+/*
+ * emit_load_volatile_arguments:
+ *
+ *  Load volatile arguments from the stack to the original input registers.
+ * Required before a tail call.
+ */
+static guint8*
+emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
+{
+       MonoMethod *method = cfg->method;
+       MonoMethodSignature *sig;
+       MonoInst *inst;
+       CallInfo *cinfo;
+       guint32 i, pos;
+
+       /* FIXME: Generate intermediate code instead */
+
+       sig = mono_method_signature (method);
+
+       /* This is the opposite of the code in emit_prolog */
+
+       pos = 0;
+
+       cinfo = calculate_sizes (sig, sig->pinvoke);
+
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               ArgInfo *ainfo = &cinfo->ret;
+               inst = cfg->vret_addr;
+               g_assert (arm_is_imm12 (inst->inst_offset));
+               ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+       }
+       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+               ArgInfo *ainfo = cinfo->args + i;
+               inst = cfg->args [pos];
+               
+               if (cfg->verbose_level > 2)
+                       g_print ("Loading argument %d (type: %d)\n", i, ainfo->regtype);
+               if (inst->opcode == OP_REGVAR) {
+                       if (ainfo->regtype == RegTypeGeneral)
+                               ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
+                       else if (ainfo->regtype == RegTypeFP) {
+                               g_assert_not_reached ();
+                       } else if (ainfo->regtype == RegTypeBase) {
+                               // FIXME:
+                               NOT_IMPLEMENTED;
+                               /*
+                               if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
+                                       ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
+                               } else {
+                                       code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
+                                       ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
+                               }
+                               */
+                       } else
+                               g_assert_not_reached ();
+               } else {
+                       if (ainfo->regtype == RegTypeGeneral) {
+                               switch (ainfo->size) {
+                               case 1:
+                               case 2:
+                                       // FIXME:
+                                       NOT_IMPLEMENTED;
+                                       break;
+                               case 8:
+                                       g_assert (arm_is_imm12 (inst->inst_offset));
+                                       ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+                                       g_assert (arm_is_imm12 (inst->inst_offset + 4));
+                                       ARM_LDR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
+                                       break;
+                               default:
+                                       if (arm_is_imm12 (inst->inst_offset)) {
+                                               ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+                                       } else {
+                                               code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
+                                               ARM_LDR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
+                                       }
+                                       break;
+                               }
+                       } else if (ainfo->regtype == RegTypeBaseGen) {
+                               // FIXME:
+                               NOT_IMPLEMENTED;
+                       } else if (ainfo->regtype == RegTypeBase) {
+                               // FIXME:
+                               NOT_IMPLEMENTED;
+                       } else if (ainfo->regtype == RegTypeFP) {
+                               g_assert_not_reached ();
+                       } else if (ainfo->regtype == RegTypeStructByVal) {
+                               int doffset = inst->inst_offset;
+                               int soffset = 0;
+                               int cur_reg;
+                               int size = 0;
+                               if (mono_class_from_mono_type (inst->inst_vtype))
+                                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
+                               for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
+                                       if (arm_is_imm12 (doffset)) {
+                                               ARM_LDR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
+                                       } else {
+                                               code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
+                                               ARM_LDR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
+                                       }
+                                       soffset += sizeof (gpointer);
+                                       doffset += sizeof (gpointer);
+                               }
+                               if (ainfo->vtsize)
+                                       // FIXME:
+                                       NOT_IMPLEMENTED;
+                       } else if (ainfo->regtype == RegTypeStructByAddr) {
+                       } else {
+                               // FIXME:
+                               NOT_IMPLEMENTED;
+                       }
+               }
+               pos ++;
+       }
+
+       g_free (cinfo);
+
+       return code;
+}
+
+#ifndef DISABLE_JIT
+
 void
 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 {
@@ -2020,6 +2526,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
        MonoCallInst *call;
        guint offset;
        guint8 *code = cfg->native_code + cfg->code_len;
+       MonoInst *last_ins = NULL;
        guint last_offset = 0;
        int max_len, cpos;
        int imm8, rot_amount;
@@ -2042,6 +2549,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                //x86_inc_mem (code, &cov->data [bb->dfn].count); 
        }
 
+    if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
+               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
+                                                        (gpointer)"mono_break");
+               code = emit_call_seq (cfg, code);
+       }
+
        MONO_BB_FOR_EACH_INS (bb, ins) {
                offset = code - cfg->native_code;
 
@@ -2177,26 +2690,43 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
                        break;
                case OP_COMPARE:
+               case OP_ICOMPARE:
                        ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
                        break;
                case OP_COMPARE_IMM:
+               case OP_ICOMPARE_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
                        break;
                case OP_BREAK:
-                       *(int*)code = 0xe7f001f0;
-                       *(int*)code = 0xef9f0001;
-                       code += 4;
+                       /*
+                        * gdb does not like encountering the hw breakpoint ins in the debugged code. 
+                        * So instead of emitting a trap, we emit a call a C function and place a 
+                        * breakpoint there.
+                        */
+                       //*(int*)code = 0xef9f0001;
+                       //code += 4;
                        //ARM_DBRK (code);
+                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
+                                                                (gpointer)"mono_break");
+                       code = emit_call_seq (cfg, code);
+                       break;
+               case OP_NOP:
+               case OP_DUMMY_USE:
+               case OP_DUMMY_STORE:
+               case OP_NOT_REACHED:
+               case OP_NOT_NULL:
                        break;
                case OP_ADDCC:
+               case OP_IADDCC:
                        ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_IADD:
                        ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ADC:
+               case OP_IADC:
                        ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ADDCC_IMM:
@@ -2205,11 +2735,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
                        break;
                case OP_ADD_IMM:
+               case OP_IADD_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
                        break;
                case OP_ADC_IMM:
+               case OP_IADC_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
@@ -2247,6 +2779,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
                        break;
                case OP_SUBCC:
+               case OP_ISUBCC:
                        ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SUBCC_IMM:
@@ -2258,14 +2791,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SBB:
+               case OP_ISBB:
                        ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SUB_IMM:
+               case OP_ISUB_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
                        break;
                case OP_SBB_IMM:
+               case OP_ISBB_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
@@ -2284,6 +2820,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_AND_IMM:
+               case OP_IAND_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
@@ -2300,6 +2837,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_OR_IMM:
+               case OP_IOR_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
@@ -2308,6 +2846,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_XOR_IMM:
+               case OP_IXOR_IMM:
                        imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
                        g_assert (imm8 >= 0);
                        ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
@@ -2316,19 +2855,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SHL_IMM:
+               case OP_ISHL_IMM:
                        if (ins->inst_imm)
                                ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
+                       else if (ins->dreg != ins->sreg1)
+                               ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
                        break;
                case OP_ISHR:
                        ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SHR_IMM:
+               case OP_ISHR_IMM:
                        if (ins->inst_imm)
                                ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
+                       else if (ins->dreg != ins->sreg1)
+                               ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
                        break;
                case OP_SHR_UN_IMM:
+               case OP_ISHR_UN_IMM:
                        if (ins->inst_imm)
                                ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
+                       else if (ins->dreg != ins->sreg1)
+                               ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
                        break;
                case OP_ISHR_UN:
                        ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
@@ -2407,6 +2955,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                         * Keep in sync with mono_arch_emit_epilog
                         */
                        g_assert (!cfg->method->save_lmf);
+
+                       code = emit_load_volatile_arguments (cfg, code);
+
                        code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
                        ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
                        mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
@@ -2431,6 +2982,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_FCALL:
                case OP_LCALL:
                case OP_VCALL:
+               case OP_VCALL2:
                case OP_VOIDCALL:
                case OP_CALL:
                        call = (MonoCallInst*)ins;
@@ -2439,34 +2991,46 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        else
                                mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
                        code = emit_call_seq (cfg, code);
+                       code = emit_move_return_value (cfg, ins, code);
                        break;
                case OP_FCALL_REG:
                case OP_LCALL_REG:
                case OP_VCALL_REG:
+               case OP_VCALL2_REG:
                case OP_VOIDCALL_REG:
                case OP_CALL_REG:
                        code = emit_call_reg (code, ins->sreg1);
+                       code = emit_move_return_value (cfg, ins, code);
                        break;
                case OP_FCALL_MEMBASE:
                case OP_LCALL_MEMBASE:
                case OP_VCALL_MEMBASE:
+               case OP_VCALL2_MEMBASE:
                case OP_VOIDCALL_MEMBASE:
                case OP_CALL_MEMBASE:
                        g_assert (arm_is_imm12 (ins->inst_offset));
                        g_assert (ins->sreg1 != ARMREG_LR);
                        call = (MonoCallInst*)ins;
                        if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                               if (cfg->compile_aot)
-                                       /* FIXME: */
-                                       cfg->disable_aot = 1;
                                ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_PC, 4);
                                ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
-                               *((gpointer*)code) = (gpointer)call->method;
+                               /* 
+                                * We can't embed the method in the code stream in PIC code, or
+                                * in gshared code.
+                                * Instead, we put it in V5 in code emitted by 
+                                * mono_arch_emit_imt_argument (), and embed NULL here to 
+                                * signal the IMT thunk that the value is in V5.
+                                */
+                               if (call->dynamic_imt_arg)
+                                       *((gpointer*)code) = NULL;
+                               else
+                                       *((gpointer*)code) = (gpointer)call->method;
                                code += 4;
                        } else {
                                ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
                                ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
                        }
+                       code = emit_move_return_value (cfg, ins, code);
                        break;
                case OP_OUTARG:
                        g_assert_not_reached ();
@@ -2515,36 +3079,45 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        code = emit_call_seq (cfg, code);
                        break;
                }
-               case OP_START_HANDLER:
-                       if (arm_is_imm12 (ins->inst_left->inst_offset)) {
-                               ARM_STR_IMM (code, ARMREG_LR, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+               case OP_START_HANDLER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+
+                       if (arm_is_imm12 (spvar->inst_offset)) {
+                               ARM_STR_IMM (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
                        } else {
-                               code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
-                               ARM_STR_REG_REG (code, ARMREG_LR, ins->inst_left->inst_basereg, ARMREG_IP);
+                               code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
+                               ARM_STR_REG_REG (code, ARMREG_LR, spvar->inst_basereg, ARMREG_IP);
                        }
                        break;
-               case OP_ENDFILTER:
+               }
+               case OP_ENDFILTER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+
                        if (ins->sreg1 != ARMREG_R0)
                                ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
-                       if (arm_is_imm12 (ins->inst_left->inst_offset)) {
-                               ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+                       if (arm_is_imm12 (spvar->inst_offset)) {
+                               ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
                        } else {
-                               g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
-                               code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
-                               ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
+                               g_assert (ARMREG_IP != spvar->inst_basereg);
+                               code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
+                               ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
                        }
                        ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
                        break;
-               case OP_ENDFINALLY:
-                       if (arm_is_imm12 (ins->inst_left->inst_offset)) {
-                               ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+               }
+               case OP_ENDFINALLY: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+
+                       if (arm_is_imm12 (spvar->inst_offset)) {
+                               ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
                        } else {
-                               g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
-                               code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
-                               ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
+                               g_assert (ARMREG_IP != spvar->inst_basereg);
+                               code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
+                               ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
                        }
                        ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
                        break;
+               }
                case OP_CALL_HANDLER: 
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
                        ARM_BL (code, 0);
@@ -2585,6 +3158,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                         * After follows the data.
                         * FIXME: add aot support.
                         */
+                       if (cfg->new_ir)
+                               mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_SWITCH, ins->inst_p0);
                        max_len += 4 * GPOINTER_TO_INT (ins->klass);
                        if (offset > (cfg->code_size - max_len - 16)) {
                                cfg->code_size += max_len;
@@ -2597,22 +3172,27 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        code += 4 * GPOINTER_TO_INT (ins->klass);
                        break;
                case OP_CEQ:
+               case OP_ICEQ:
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
                        break;
                case OP_CLT:
+               case OP_ICLT:
                        ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
                        break;
                case OP_CLT_UN:
+               case OP_ICLT_UN:
                        ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
                        break;
                case OP_CGT:
+               case OP_ICGT:
                        ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
                        break;
                case OP_CGT_UN:
+               case OP_ICGT_UN:
                        ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
                        ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
                        break;
@@ -2628,11 +3208,27 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_COND_EXC_LE_UN:
                        EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
                        break;
+               case OP_COND_EXC_IEQ:
+               case OP_COND_EXC_INE_UN:
+               case OP_COND_EXC_ILT:
+               case OP_COND_EXC_ILT_UN:
+               case OP_COND_EXC_IGT:
+               case OP_COND_EXC_IGT_UN:
+               case OP_COND_EXC_IGE:
+               case OP_COND_EXC_IGE_UN:
+               case OP_COND_EXC_ILE:
+               case OP_COND_EXC_ILE_UN:
+                       EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
+                       break;
                case OP_COND_EXC_C:
                case OP_COND_EXC_OV:
                case OP_COND_EXC_NC:
                case OP_COND_EXC_NO:
-                       g_assert_not_reached ();
+               case OP_COND_EXC_IC:
+               case OP_COND_EXC_IOV:
+               case OP_COND_EXC_INC:
+               case OP_COND_EXC_INO:
+                       /* FIXME: */
                        break;
                case OP_IBEQ:
                case OP_IBNE_UN:
@@ -2677,12 +3273,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        break;
                case OP_STORER8_MEMBASE_REG:
-                       g_assert (arm_is_fpimm8 (ins->inst_offset));
-                       ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+                       /* This is generated by the local regalloc pass which runs after the lowering pass */
+                       if (!arm_is_fpimm8 (ins->inst_offset)) {
+                               code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+                               ARM_STFD (code, ins->sreg1, ARMREG_LR, 0);
+                       } else {
+                               ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+                       }
                        break;
                case OP_LOADR8_MEMBASE:
-                       g_assert (arm_is_fpimm8 (ins->inst_offset));
-                       ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+                       /* This is generated by the local regalloc pass which runs after the lowering pass */
+                       if (!arm_is_fpimm8 (ins->inst_offset)) {
+                               code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+                               ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
+                       } else {
+                               ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+                       }
                        break;
                case OP_STORER4_MEMBASE_REG:
                        g_assert (arm_is_fpimm8 (ins->inst_offset));
@@ -2727,7 +3333,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 #elif defined(ARM_FPU_VFP)
                case OP_R8CONST:
                        if (cfg->compile_aot) {
-                               ARM_LDFD (code, ins->dreg, ARMREG_PC, 0);
+                               ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
                                ARM_B (code, 1);
                                *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
                                code += 4;
@@ -2812,31 +3418,35 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert_not_reached ();
                        /* Implemented as helper calls */
                        break;
-               case OP_LCONV_TO_OVF_I: {
-#if ARM_PORT
-                       guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
-                       // Check if its negative
-                       ppc_cmpi (code, 0, 0, ins->sreg1, 0);
-                       negative_branch = code;
-                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
-                       // Its positive msword == 0
-                       ppc_cmpi (code, 0, 0, ins->sreg2, 0);
-                       msword_positive_branch = code;
-                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
-
-                       ovf_ex_target = code;
-                       //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
-                       // Negative
-                       ppc_patch (negative_branch, code);
-                       ppc_cmpi (code, 0, 0, ins->sreg2, -1);
-                       msword_negative_branch = code;
-                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
-                       ppc_patch (msword_negative_branch, ovf_ex_target);
+               case OP_LCONV_TO_OVF_I:
+               case OP_LCONV_TO_OVF_I4_2: {
+                       guint32 *high_bit_not_set, *valid_negative, *invalid_negative, *valid_positive;
+                       /* 
+                        * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
+                        */
+
+                       ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
+                       high_bit_not_set = code;
+                       ARM_B_COND (code, ARMCOND_GE, 0); /*branch if bit 31 of the lower part is not set*/
+
+                       ARM_CMN_REG_IMM8 (code, ins->sreg2, 1); /*This have the same effect as CMP reg, 0xFFFFFFFF */
+                       valid_negative = code;
+                       ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0xFFFFFFFF (lower part has bit 31 set) */
+                       invalid_negative = code;
+                       ARM_B_COND (code, ARMCOND_AL, 0);
                        
-                       ppc_patch (msword_positive_branch, code);
-                       if (ins->dreg != ins->sreg1)
-                               ppc_mr (code, ins->dreg, ins->sreg1);
-#endif
+                       arm_patch (high_bit_not_set, code);
+
+                       ARM_CMP_REG_IMM8 (code, ins->sreg2, 0);
+                       valid_positive = code;
+                       ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0 (lower part has bit 31 clear)*/
+
+                       arm_patch (invalid_negative, code);
+                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_AL, "OverflowException");
+
+                       arm_patch (valid_negative, code);
+                       arm_patch (valid_positive, code);
+
                        if (ins->dreg != ins->sreg1)
                                ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
                        break;
@@ -2879,9 +3489,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert_not_reached ();
                        break;
                case OP_FCOMPARE:
-                       /* each fp compare op needs to do its own */
-                       g_assert_not_reached ();
-                       //ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
+#ifdef ARM_FPU_FPA
+                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
+#elif defined(ARM_FPU_VFP)
+                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
+#endif
                        break;
                case OP_FCEQ:
 #ifdef ARM_FPU_FPA
@@ -2939,97 +3551,39 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                 * V        Unordered               ARMCOND_VS
                 */
                case OP_FBEQ:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
                        break;
                case OP_FBNE_UN:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
                        break;
                case OP_FBLT:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
                        break;
                case OP_FBLT_UN:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
                        break;
                case OP_FBGT:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg2, ins->sreg1);
-#endif
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
-                       break;
                case OP_FBGT_UN:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg2, ins->sreg1);
-#endif
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
+               case OP_FBLE:
+               case OP_FBLE_UN:
+                       g_assert_not_reached ();
                        break;
                case OP_FBGE:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
                        break;
                case OP_FBGE_UN:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg1, ins->sreg2);
-#endif
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
                        EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
                        break;
-               case OP_FBLE:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg2, ins->sreg1);
-#endif
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */
-                       break;
-               case OP_FBLE_UN:
-#ifdef ARM_FPU_FPA
-                       ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
-#elif defined(ARM_FPU_VFP)
-                       ARM_CMPD (code, ins->sreg2, ins->sreg1);
-#endif
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
-                       EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */
-                       break;
+
                case OP_CKFINITE: {
-                       /*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 (OP_IBEQ - OP_IBEQ, "ArithmeticException");*/
+#ifdef ARM_FPU_FPA
+                       if (ins->dreg != ins->sreg1)
+                               ARM_MVFD (code, ins->dreg, ins->sreg1);
+#else
                        g_assert_not_reached ();
+#endif
                        break;
                }
                default:
@@ -3045,15 +3599,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
               
                cpos += max_len;
 
+               last_ins = ins;
                last_offset = offset;
        }
 
        cfg->code_len = code - cfg->native_code;
 }
 
+#endif /* DISABLE_JIT */
+
 void
 mono_arch_register_lowlevel_calls (void)
 {
+       /* The signature doesn't matter */
+       mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
 }
 
 #define patch_lis_ori(ip,val) do {\
@@ -3224,7 +3783,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
         */
        max_offset = 0;
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
+               MonoInst *ins = bb->code;
                bb->max_offset = max_offset;
 
                if (cfg->prof_options & MONO_PROFILE_COVERAGE)
@@ -3234,6 +3793,20 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
        }
 
+       /* store runtime generic context */
+       if (cfg->rgctx_var) {
+               MonoInst *ins = cfg->rgctx_var;
+
+               g_assert (ins->opcode == OP_REGOFFSET);
+
+               if (arm_is_imm12 (ins->inst_offset)) {
+                       ARM_STR_IMM (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
+               } else {
+                       code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+                       ARM_STR_REG_REG (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ARMREG_LR);
+               }
+       }
+
        /* load arguments allocated to register from the stack */
        pos = 0;
 
@@ -3241,7 +3814,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                ArgInfo *ainfo = &cinfo->ret;
-               inst = cfg->ret;
+               inst = cfg->vret_addr;
                g_assert (arm_is_imm12 (inst->inst_offset));
                ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
        }
@@ -3370,8 +3943,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                int soffset = 0;
                                int cur_reg;
                                int size = 0;
-                               if (mono_class_from_mono_type (inst->inst_vtype))
-                                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
+                               size = mini_type_stack_size_full (cfg->generic_sharing_context, inst->inst_vtype, NULL, sig->pinvoke);
                                for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
                                        if (arm_is_imm12 (doffset)) {
                                                ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
@@ -3418,9 +3990,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
                /* *(lmf_addr) = r1 */
                ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
-               /* save method info */
-               code = mono_arm_emit_load_imm (code, ARMREG_R2, GPOINTER_TO_INT (method));
-               ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method));
+               /* Skip method (only needed for trampoline LMF frames) */
                ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
                /* save the current IP */
                ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
@@ -3543,13 +4113,12 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
      
        /* 
         * make sure we have enough space for exceptions
-        * 12 is the simulated call to throw_exception_by_name
         */
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                if (patch_info->type == MONO_PATCH_INFO_EXC) {
                        i = exception_id_by_name (patch_info->data.target);
                        if (!exc_throw_found [i]) {
-                               max_epilog_size += 12;
+                               max_epilog_size += 32;
                                exc_throw_found [i] = TRUE;
                        }
                }
@@ -3567,8 +4136,9 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
                case MONO_PATCH_INFO_EXC: {
+                       MonoClass *exc_class;
                        unsigned char *ip = patch_info->ip.i + cfg->native_code;
-                       const char *ex_name = patch_info->data.target;
+
                        i = exception_id_by_name (patch_info->data.target);
                        if (exc_throw_pos [i]) {
                                arm_patch (ip, exc_throw_pos [i]);
@@ -3578,17 +4148,17 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                                exc_throw_pos [i] = code;
                        }
                        arm_patch (ip, code);
-                       //*(int*)code = 0xef9f0001;
-                       //code += 4;
-                       ARM_NOP (code);
-                       /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
+
+                       exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
+                       g_assert (exc_class);
+
+                       ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
                        ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-                       /* we got here from a conditional call, so the calling ip is set in lr already */
                        patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
-                       patch_info->data.name = "mono_arch_throw_exception_by_name";
+                       patch_info->data.name = "mono_arch_throw_corlib_exception";
                        patch_info->ip.i = code - cfg->native_code;
-                       ARM_B (code, 0);
-                       *(gconstpointer*)code = ex_name;
+                       ARM_BL (code, 0);
+                       *(guint32*)(gpointer)code = exc_class->type_token;
                        code += 4;
                        break;
                }
@@ -3651,6 +4221,13 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethod
        return NULL;
 }
 
+MonoInst*
+mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       /* FIXME: */
+       return NULL;
+}
+
 gboolean
 mono_arch_print_tree (MonoInst *tree, int arity)
 {
@@ -3691,8 +4268,42 @@ mono_arch_fixup_jinfo (MonoCompile *cfg)
 #ifdef MONO_ARCH_HAVE_IMT
 
 void
-mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
+mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 {
+       if (cfg->compile_aot) {
+               int method_reg = mono_regstate_next_int (cfg->rs);
+               MonoInst *ins;
+
+               call->dynamic_imt_arg = TRUE;
+
+               MONO_INST_NEW (cfg, ins, OP_AOTCONST);
+               ins->dreg = method_reg;
+               ins->inst_p0 = call->method;
+               ins->inst_c1 = MONO_PATCH_INFO_METHODCONST;
+               MONO_ADD_INS (cfg->cbb, ins);
+
+               mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
+       } else if (cfg->generic_context) {
+
+               /* Always pass in a register for simplicity */
+               call->dynamic_imt_arg = TRUE;
+
+               cfg->uses_rgctx_reg = TRUE;
+
+               if (imt_arg) {
+                       mono_call_inst_add_outarg_reg (cfg, call, imt_arg->dreg, ARMREG_V5, FALSE);
+               } else {
+                       MonoInst *ins;
+                       int method_reg = mono_alloc_preg (cfg);
+
+                       MONO_INST_NEW (cfg, ins, OP_PCONST);
+                       ins->inst_p0 = call->method;
+                       ins->dreg = method_reg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+
+                       mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
+               }
+       }
 }
 
 MonoMethod*
@@ -3705,18 +4316,27 @@ mono_arch_find_imt_method (gpointer *regs, guint8 *code)
                g_warning ("invalid code stream, instruction before IMT value is not a LDC in %s() (code %p value 0: 0x%x -1: 0x%x -2: 0x%x)", __FUNCTION__, code, code_ptr [2], code_ptr [1], code_ptr [0]);
                g_assert (IS_LDR_PC (code_ptr [0]));
        }
-       return (MonoMethod*) code_ptr [1];
+       if (code_ptr [1] == 0)
+               /* This is AOTed code, the IMT method is in V5 */
+               return (MonoMethod*)regs [ARMREG_V5];
+       else
+               return (MonoMethod*) code_ptr [1];
 }
 
 MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
 {
-       return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
+       return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
 }
 
+MonoVTable*
+mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
+{
+       return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
+}
 
 #define ENABLE_WRONG_METHOD_CHECK 0
-#define BASE_SIZE (4 * 4)
+#define BASE_SIZE (6 * 4)
 #define BSEARCH_ENTRY_SIZE (4 * 4)
 #define CMP_SIZE (3 * 4)
 #define BRANCH_SIZE (1 * 4)
@@ -3779,6 +4399,10 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        vtable_target = code;
        ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
 
+       /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
+       ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
+       ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
+
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                arminstr_t *imt_method = NULL;
@@ -3869,4 +4493,8 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
 
 #endif
 
-
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+       return ctx->regs [reg];
+}