2008-09-27 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / mini-ppc.c
index a304277dfd7b6eb0b0f5d835c43c25fb4ae947e1..bed880b6b605dd1541958e66109b97e640c957a6 100644 (file)
 
 #include "mini-ppc.h"
 #include "inssel.h"
-#include "cpu-g4.h"
+#include "cpu-ppc.h"
 #include "trace.h"
 #ifdef __APPLE__
 #include <sys/sysctl.h>
 #endif
 
+/* From ir-emit.h */
+static inline guint32
+alloc_ireg (MonoCompile *cfg)
+{
+       return cfg->next_vreg ++;
+}
+
+static inline guint32
+alloc_lreg (MonoCompile *cfg)
+{
+#if SIZEOF_VOID_P == 8
+       return cfg->next_vreg ++;
+#else
+       /* Use a pair of consecutive vregs */
+       guint32 res = cfg->next_vreg;
+
+       cfg->next_vreg += 3;
+
+       return res;
+#endif
+}
+
+static inline guint32
+alloc_freg (MonoCompile *cfg)
+{
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* Allocate an lvreg so float ops can be decomposed into long ops */
+       return alloc_lreg (cfg);
+#else
+       /* Allocate these from the same pool as the int regs */
+       return cfg->next_vreg ++;
+#endif
+}
+
+static inline guint32
+alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
+{
+       switch (stack_type) {
+       case STACK_I4:
+       case STACK_PTR:
+       case STACK_MP:
+       case STACK_OBJ:
+               return alloc_ireg (cfg);
+       case STACK_R8:
+               return alloc_freg (cfg);
+       case STACK_I8:
+               return alloc_lreg (cfg);
+       case STACK_VTYPE:
+               return alloc_ireg (cfg);
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
+#else
+#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
+#endif
+
+#define NEW_VARLOADA(cfg,dest,var,vartype) do {        \
+        MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
+               (dest)->inst_p0 = (var); \
+               (var)->flags |= MONO_INST_INDIRECT;     \
+               (dest)->type = STACK_MP;        \
+               (dest)->klass = (var)->klass;   \
+        (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
+               if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
+       } while (0)
+
+#define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
+
 #define FORCE_INDIR_CALL 1
 
 enum {
@@ -32,6 +104,11 @@ enum {
        TLS_MODE_DARWIN_G5
 };
 
+/* This mutex protects architecture specific caches */
+#define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
+#define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
+static CRITICAL_SECTION mini_arch_mutex;
+
 int mono_exc_esp_offset = 0;
 static int tls_mode = TLS_MODE_DETECT;
 static int lmf_pthread_key = -1;
@@ -194,9 +271,9 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        for (k = 0; k < param_count; k++) {
                
                if (csig->pinvoke)
-                       size = mono_type_native_stack_size (csig->params [k], &align);
+                       size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
                else
-                       size = mono_type_stack_size (csig->params [k], &align);
+                       size = mini_type_stack_size (NULL, csig->params [k], &align);
 
                /* ignore alignment for now */
                align = 1;
@@ -218,6 +295,150 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        return frame_size;
 }
 
+gpointer
+mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
+{
+       char *o = NULL;
+       int reg, offset = 0;
+       guint32* code = (guint32*)code_ptr;
+
+       *displacement = 0;
+
+       /* This is the 'blrl' instruction */
+       --code;
+
+       /* Sanity check: instruction must be 'blrl' */
+       if (*code != 0x4e800021)
+               return NULL;
+
+       /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
+       if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
+               return NULL;
+       }
+
+       /* OK, we're now at the 'blrl' instruction. Now walk backwards
+       till we get to a 'mtlr rA' */
+       for (; --code;) {
+               if((*code & 0x7c0803a6) == 0x7c0803a6) {
+                       gint16 soff;
+                       /* Here we are: we reached the 'mtlr rA'.
+                       Extract the register from the instruction */
+                       reg = (*code & 0x03e00000) >> 21;
+                       --code;
+                       /* ok, this is a lwz reg, offset (vtreg) 
+                        * it is emitted with:
+                        * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
+                        */
+                       soff = (*code & 0xffff);
+                       offset = soff;
+                       reg = (*code >> 16) & 0x1f;
+                       g_assert (reg != ppc_r1);
+                       /*g_print ("patching reg is %d\n", reg);*/
+                       if (reg >= 13) {
+                               MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
+                               /* saved in the MonoLMF structure */
+                               o = (gpointer)lmf->iregs [reg - 13];
+                       } else {
+                               o = regs [reg];
+                       }
+                       break;
+               }
+       }
+       *displacement = offset;
+       return o;
+}
+
+gpointer*
+mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
+{
+       gpointer vt;
+       int displacement;
+       vt = mono_arch_get_vcall_slot (code, regs, &displacement);
+       if (!vt)
+               return NULL;
+       return (gpointer*)((char*)vt + displacement);
+}
+
+#define MAX_ARCH_DELEGATE_PARAMS 7
+
+gpointer
+mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
+{
+       guint8 *code, *start;
+
+       /* FIXME: Support more cases */
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               return NULL;
+
+       if (has_target) {
+               static guint8* cached = NULL;
+               mono_mini_arch_lock ();
+               if (cached) {
+                       mono_mini_arch_unlock ();
+                       return cached;
+               }
+               
+               start = code = mono_global_codeman_reserve (16);
+
+               /* Replace the this argument with the target */
+               ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
+               ppc_mtctr (code, ppc_r0);
+               ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
+               ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+               g_assert ((code - start) <= 16);
+
+               mono_arch_flush_icache (start, 16);
+               cached = start;
+               mono_mini_arch_unlock ();
+               return cached;
+       } else {
+               static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
+               int size, i;
+
+               if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
+                       return NULL;
+               for (i = 0; i < sig->param_count; ++i)
+                       if (!mono_is_regsize_var (sig->params [i]))
+                               return NULL;
+
+               mono_mini_arch_lock ();
+               code = cache [sig->param_count];
+               if (code) {
+                       mono_mini_arch_unlock ();
+                       return code;
+               }
+
+               size = 12 + sig->param_count * 4;
+               start = code = mono_global_codeman_reserve (size);
+
+               ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
+               ppc_mtctr (code, ppc_r0);
+               /* slide down the arguments */
+               for (i = 0; i < sig->param_count; ++i) {
+                       ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
+               }
+               ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+               g_assert ((code - start) <= size);
+
+               mono_arch_flush_icache (start, size);
+               cache [sig->param_count] = start;
+               mono_mini_arch_unlock ();
+               return start;
+       }
+       return NULL;
+}
+
+gpointer
+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))
+               return (gpointer)regs [ppc_r4];
+       return (gpointer)regs [ppc_r3];
+}
+
 /*
  * Initialize the cpu to execute managed code.
  */
@@ -226,6 +447,24 @@ mono_arch_cpu_init (void)
 {
 }
 
+/*
+ * Initialize architecture specific code.
+ */
+void
+mono_arch_init (void)
+{
+       InitializeCriticalSection (&mini_arch_mutex);   
+}
+
+/*
+ * Cleanup architecture specific code.
+ */
+void
+mono_arch_cleanup (void)
+{
+       DeleteCriticalSection (&mini_arch_mutex);
+}
+
 /*
  * This function returns the optimizations supported on this cpu.
  */
@@ -303,7 +542,8 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
        int i, top = 32;
        if (cfg->frame_reg != ppc_sp)
                top = 31;
-       for (i = 13; i < top; ++i)
+       /* ppc_r13 is used by the system on PPC EABI */
+       for (i = 14; i < top; ++i)
                regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
 
        return regs;
@@ -337,11 +577,12 @@ mono_arch_flush_icache (guint8 *code, gint size)
 
        if (!cachelinesize) {
 #ifdef __APPLE__
-               int mib [3], len;
+               int mib [3];
+               size_t len;
                mib [0] = CTL_HW;
                mib [1] = HW_CACHELINE;
                len = sizeof (cachelinesize);
-               if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
+               if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
                        perror ("sysctl");
                        cachelinesize = 128;
                } else {
@@ -390,8 +631,10 @@ mono_arch_flush_icache (guint8 *code, gint size)
        asm ("isync");
 }
 
-#define NOT_IMPLEMENTED(x) \
-                g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
+void
+mono_arch_flush_register_windows (void)
+{
+}
 
 #ifdef __APPLE__
 #define ALWAYS_ON_STACK(s) s
@@ -465,21 +708,24 @@ add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
 }
 
 #if __APPLE__
-/* size == 4 is checked already */
 static gboolean
-has_only_a_r4_field (MonoClass *klass)
+has_only_a_r48_field (MonoClass *klass)
 {
        gpointer iter;
        MonoClassField *f;
+       gboolean have_field = FALSE;
        iter = NULL;
        while ((f = mono_class_get_fields (klass, &iter))) {
                if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
-                       if (!f->type->byref && f->type->type == MONO_TYPE_R4)
-                               return TRUE;
-                       return FALSE;
+                       if (have_field)
+                               return FALSE;
+                       if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
+                               have_field = TRUE;
+                       else
+                               return FALSE;
                }
        }
-       return FALSE;
+       return have_field;
 }
 #endif
 
@@ -508,10 +754,11 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
        }
         DEBUG(printf("params: %d\n", sig->param_count));
        for (i = 0; i < sig->param_count; ++i) {
-               if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+               if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
                         /* Prevent implicit arguments and sig_cookie from
                           being passed in registers */
                         gr = PPC_LAST_ARG_REG + 1;
+                       /* FIXME: don't we have to set fr, too? */
                         /* Emit the signature cookie just before the implicit arguments */
                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
                 }
@@ -574,8 +821,8 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                        else
                            size = mono_class_value_size (klass, NULL);
 #if __APPLE__
-                       if (size == 4 && has_only_a_r4_field (klass)) {
-                               cinfo->args [n].size = 4;
+                       if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
+                               cinfo->args [n].size = size;
 
                                /* It was 7, now it is 8 in LinuxPPC */
                                if (fr <= PPC_LAST_FPARG_REG) {
@@ -583,12 +830,14 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                                        cinfo->args [n].reg = fr;
                                        fr ++;
                                        FP_ALSO_IN_REG (gr ++);
-                                       ALWAYS_ON_STACK (stack_size += 4);
+                                       if (size == 8)
+                                               FP_ALSO_IN_REG (gr ++);
+                                       ALWAYS_ON_STACK (stack_size += size);
                                } else {
                                        cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
                                        cinfo->args [n].regtype = RegTypeBase;
                                        cinfo->args [n].reg = ppc_sp; /* in the caller*/
-                                       stack_size += 4;
+                                       stack_size += 8;
                                }
                                n++;
                                break;
@@ -600,21 +849,22 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                        {
                                int align_size = size;
                                int nwords = 0;
+                               int rest = PPC_LAST_ARG_REG - gr + 1;
+                               int n_in_regs;
                                align_size += (sizeof (gpointer) - 1);
                                align_size &= ~(sizeof (gpointer) - 1);
                                nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
+                               n_in_regs = rest >= nwords? nwords: rest;
                                cinfo->args [n].regtype = RegTypeStructByVal;
                                if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
                                        cinfo->args [n].size = 0;
                                        cinfo->args [n].vtsize = nwords;
                                } else {
-                                       int rest = PPC_LAST_ARG_REG - gr + 1;
-                                       int n_in_regs = rest >= nwords? nwords: rest;
                                        cinfo->args [n].size = n_in_regs;
                                        cinfo->args [n].vtsize = nwords - n_in_regs;
                                        cinfo->args [n].reg = gr;
-                                       gr += n_in_regs;
                                }
+                               gr += n_in_regs;
                                cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
                                /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
                                stack_size += nwords * sizeof (gpointer);
@@ -703,6 +953,14 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                }
        }
 
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+               /* Prevent implicit arguments and sig_cookie from
+                  being passed in registers */
+               gr = PPC_LAST_ARG_REG + 1;
+               /* Emit the signature cookie just before the implicit arguments */
+               add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
+       }
+
        {
                simpletype = mono_type_get_underlying_type (sig->ret)->type;
                switch (simpletype) {
@@ -758,6 +1016,34 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
        return cinfo;
 }
 
+static void
+allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
+{
+#if !PPC_PASS_STRUCTS_BY_VALUE
+       MonoMethodSignature *sig = mono_method_signature (cfg->method);
+       int num_structs = 0;
+       int i;
+
+       if (!(cfg->flags & MONO_CFG_HAS_TAIL))
+               return;
+
+       for (i = 0; i < sig->param_count; ++i) {
+               MonoType *type = mono_type_get_underlying_type (sig->params [i]);
+               if (type->type == MONO_TYPE_VALUETYPE)
+                       num_structs++;
+       }
+
+       if (num_structs) {
+               cfg->tailcall_valuetype_addrs =
+                       mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
+               for (i = 0; i < num_structs; ++i) {
+                       cfg->tailcall_valuetype_addrs [i] =
+                               mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                       cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
+               }
+       }
+#endif
+}
 
 /*
  * Set var information according to the calling convention. ppc version.
@@ -771,6 +1057,10 @@ mono_arch_allocate_vars (MonoCompile *m)
        MonoInst *inst;
        int i, offset, size, align, curinst;
        int frame_reg = ppc_sp;
+       gint32 *offsets;
+       guint32 locals_stack_size, locals_stack_align;
+
+       allocate_tailcall_valuetype_addrs (m);
 
        m->flags |= MONO_CFG_HAS_SPILLUP;
 
@@ -813,15 +1103,20 @@ mono_arch_allocate_vars (MonoCompile *m)
        curinst = 0;
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                m->ret->opcode = OP_REGVAR;
-               m->ret->inst_c0 = ppc_r3;
+               m->ret->inst_c0 = m->ret->dreg = ppc_r3;
        } else {
-               /* FIXME: handle long and FP values */
+               /* FIXME: handle long values? */
                switch (mono_type_get_underlying_type (sig->ret)->type) {
                case MONO_TYPE_VOID:
                        break;
+               case MONO_TYPE_R4:
+               case MONO_TYPE_R8:
+                       m->ret->opcode = OP_REGVAR;
+                       m->ret->inst_c0 = m->ret->dreg = ppc_f1;
+                       break;
                default:
                        m->ret->opcode = OP_REGVAR;
-                       m->ret->inst_c0 = ppc_r3;
+                       m->ret->inst_c0 = m->ret->dreg = ppc_r3;
                        break;
                }
        }
@@ -863,42 +1158,52 @@ mono_arch_allocate_vars (MonoCompile *m)
         }
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               inst = m->ret;
                offset += sizeof(gpointer) - 1;
                offset &= ~(sizeof(gpointer) - 1);
-               inst->inst_offset = offset;
-               inst->opcode = OP_REGOFFSET;
-               inst->inst_basereg = frame_reg;
+
+               if (m->new_ir) {
+                       m->vret_addr->opcode = OP_REGOFFSET;
+                       m->vret_addr->inst_basereg = frame_reg;
+                       m->vret_addr->inst_offset = offset;
+
+                       if (G_UNLIKELY (m->verbose_level > 1)) {
+                               printf ("vret_addr =");
+                               mono_print_ins (m->vret_addr);
+                       }
+               } else {
+                       inst = m->ret;
+                       inst->inst_offset = offset;
+                       inst->opcode = OP_REGOFFSET;
+                       inst->inst_basereg = frame_reg;
+               }
+
                offset += sizeof(gpointer);
                if (sig->call_convention == MONO_CALL_VARARG)
                        m->sig_cookie += sizeof (gpointer);
        }
 
-       curinst = m->locals_start;
-       for (i = curinst; i < m->num_varinfo; ++i) {
-               inst = m->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);
-               else
-                       size = mono_type_size (inst->inst_vtype, &align);
-
-               offset += align - 1;
-               offset &= ~(align - 1);
-               inst->inst_offset = offset;
-               inst->opcode = OP_REGOFFSET;
-               inst->inst_basereg = frame_reg;
-               offset += size;
-               //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
+       offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
+       if (locals_stack_align) {
+               offset += (locals_stack_align - 1);
+               offset &= ~(locals_stack_align - 1);
+       }
+       for (i = m->locals_start; i < m->num_varinfo; i++) {
+               if (offsets [i] != -1) {
+                       MonoInst *inst = m->varinfo [i];
+                       inst->opcode = OP_REGOFFSET;
+                       inst->inst_basereg = frame_reg;
+                       inst->inst_offset = offset + offsets [i];
+                       /*
+                       g_print ("allocating local %d (%s) to %d\n",
+                               i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
+                       */
+               }
        }
+       offset += locals_stack_size;
 
        curinst = 0;
        if (sig->hasthis) {
-               inst = m->varinfo [curinst];
+               inst = m->args [curinst];
                if (inst->opcode != OP_REGVAR) {
                        inst->opcode = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
@@ -913,11 +1218,16 @@ mono_arch_allocate_vars (MonoCompile *m)
        }
 
        for (i = 0; i < sig->param_count; ++i) {
-               inst = m->varinfo [curinst];
+               inst = m->args [curinst];
                if (inst->opcode != OP_REGVAR) {
                        inst->opcode = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
-                       size = mono_type_size (sig->params [i], &align);
+                       if (sig->pinvoke) {
+                               size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
+                               inst->backend.is_pinvoke = 1;
+                       } else {
+                               size = mono_type_size (sig->params [i], &align);
+                       }
                        offset += align - 1;
                        offset &= ~(align - 1);
                        inst->inst_offset = offset;
@@ -935,6 +1245,23 @@ mono_arch_allocate_vars (MonoCompile *m)
        /* change sign? */
        m->stack_offset = offset;
 
+       if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
+               CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
+
+               m->sig_cookie = cinfo->sig_cookie.offset;
+
+               g_free(cinfo);
+        }
+}
+
+void
+mono_arch_create_vars (MonoCompile *cfg)
+{
+       MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+       if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
+               cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
+       }
 }
 
 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
@@ -975,7 +1302,7 @@ 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;
-                       
+                       arg->inst_call = call;
                        /* prepend, so they get reversed */
                        arg->next = call->out_args;
                        call->out_args = arg;
@@ -991,7 +1318,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                        arg->inst_left = in;
                        arg->inst_call = call;
                        arg->type = in->type;
-                       /* prepend, we'll need to reverse them later */
+                       /* prepend, so they get reversed */
                        arg->next = call->out_args;
                        call->out_args = arg;
                        if (ainfo->regtype == RegTypeGeneral) {
@@ -1061,6 +1388,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                }
                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;
@@ -1073,6 +1401,254 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
        return call;
 }
 
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+       int sig_reg = mono_alloc_ireg (cfg);
+
+       MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
+                       ppc_r1, cinfo->sig_cookie.offset, sig_reg);
+}
+
+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 = mono_type_get_underlying_type (t);
+
+               if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
+                       emit_sig_cookie (cfg, call, cinfo);
+
+               in = call->args [i];
+
+               if (ainfo->regtype == 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 + 1, 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, FALSE);
+                       } 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);
+                       }
+               } else if (ainfo->regtype == RegTypeStructByAddr) {
+                       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);
+               } else if (ainfo->regtype == RegTypeStructByVal) {
+                       /* this is further handled in mono_arch_emit_outarg_vt () */
+                       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);
+               } else if (ainfo->regtype == RegTypeBase) {
+                       if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, 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, ppc_r1, ainfo->offset, in->dreg);
+                               else
+                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
+                       } else {
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
+                       }
+               } else if (ainfo->regtype == RegTypeFP) {
+                       if (t->type == MONO_TYPE_VALUETYPE) {
+                               /* this is further handled in mono_arch_emit_outarg_vt () */
+                               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);
+
+                               cfg->flags |= MONO_CFG_HAS_FPOUT;
+                       } else {
+                               int dreg = mono_alloc_freg (cfg);
+
+                               if (ainfo->size == 4) {
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
+                               } else {
+                                       MONO_INST_NEW (cfg, ins, OP_FMOVE);
+                                       ins->dreg = dreg;
+                                       ins->sreg1 = in->dreg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                               }
+
+                               mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
+                               cfg->flags |= MONO_CFG_HAS_FPOUT;
+                       }
+               } else {
+                       g_assert_not_reached ();
+               }
+       }
+
+       /* Emit the signature cookie in the case that there is no
+          additional argument */
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
+               emit_sig_cookie (cfg, call, cinfo);
+
+       if (cinfo->struct_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->struct_ret, FALSE);
+       }
+
+       call->stack_usage = cinfo->stack_usage;
+       cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
+       cfg->flags |= MONO_CFG_HAS_CALLS;
+
+       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;
+
+       if (ainfo->regtype == RegTypeStructByVal) {
+               guint32 size = 0;
+               soffset = 0;
+#ifdef __APPLE__
+               /*
+                * Darwin pinvokes needs some special handling for 1
+                * and 2 byte arguments
+                */
+               g_assert (ins->klass);
+               if (call->signature->pinvoke)
+                       size =  mono_class_native_size (ins->klass, NULL);
+               if (size == 2 || size == 1) {
+                       int tmpr = mono_alloc_ireg (cfg);
+                       if (size == 1)
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
+                       else
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
+                       dreg = mono_alloc_ireg (cfg);
+                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
+                       mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
+               } else
+#endif
+                       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);
+                       }
+               if (ovf_size != 0)
+                       mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+       } else if (ainfo->regtype == RegTypeFP) {
+               int tmpr = mono_alloc_freg (cfg);
+               if (ainfo->size == 4)
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
+               else
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
+               dreg = mono_alloc_freg (cfg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
+               mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
+       } else {
+               MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
+               MonoInst *load;
+               guint32 size;
+
+               /* FIXME: alignment? */
+               if (call->signature->pinvoke) {
+                       size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
+                       vtcopy->backend.is_pinvoke = 1;
+               } else {
+                       size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
+               }
+               if (size > 0)
+                       g_assert (ovf_size > 0);
+
+               EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
+               mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
+
+               if (ainfo->offset)
+                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
+               else
+                       mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
+       }
+}
+
+void
+mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
+{
+       MonoType *ret = mono_type_get_underlying_type (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;
+               }
+               if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
+                       MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
+                       return;
+               }
+       }
+       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+}
+
+/* FIXME: this is just a useless hint: fix the interface to include the opcode */
+gboolean
+mono_arch_is_inst_imm (gint64 imm)
+{
+       return TRUE;
+}
+
 /*
  * Allow tracing to work with this interface (with an optional argument)
  */
@@ -1117,7 +1693,7 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
                cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
                code = cfg->native_code + offset;
        }
-handle_enum:
+
        switch (rtype) {
        case MONO_TYPE_VOID:
                /* special case string .ctor icall */
@@ -1274,14 +1850,17 @@ if (ins->flags & MONO_INST_BRLABEL) { \
 
 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
 
-static void
-peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
+void
+mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
 {
-       MonoInst *ins, *last_ins = NULL;
-       ins = bb->code;
+}
 
-       while (ins) {
+void
+mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+       MonoInst *ins, *n, *last_ins = NULL;
 
+       MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
                switch (ins->opcode) {
                case OP_MUL_IMM: 
                        /* remove unnecessary multiplication with 1 */
@@ -1289,8 +1868,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                                if (ins->dreg != ins->sreg1) {
                                        ins->opcode = OP_MOVE;
                                } else {
-                                       last_ins->next = ins->next;                             
-                                       ins = ins->next;                                
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                }
                        } else {
@@ -1312,8 +1890,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                            ins->inst_basereg == last_ins->inst_destbasereg &&
                            ins->inst_offset == last_ins->inst_offset) {
                                if (ins->dreg == last_ins->sreg1) {
-                                       last_ins->next = ins->next;                             
-                                       ins = ins->next;                                
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                } else {
                                        //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
@@ -1336,8 +1913,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                              ins->inst_offset == last_ins->inst_offset) {
 
                                if (ins->dreg == last_ins->dreg) {
-                                       last_ins->next = ins->next;                             
-                                       ins = ins->next;                                
+                                       MONO_DELETE_INS (bb, ins);
                                        continue;
                                } else {
                                        ins->opcode = OP_MOVE;
@@ -1370,7 +1946,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
                                        ins->inst_basereg == last_ins->inst_destbasereg &&
                                        ins->inst_offset == last_ins->inst_offset) {
-                               ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
+                               ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
                                ins->sreg1 = last_ins->sreg1;                           
                        }
                        break;
@@ -1379,22 +1955,17 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
                                        ins->inst_basereg == last_ins->inst_destbasereg &&
                                        ins->inst_offset == last_ins->inst_offset) {
-                               ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
+                               ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
                                ins->sreg1 = last_ins->sreg1;                           
                        }
                        break;
-               case CEE_CONV_I4:
-               case CEE_CONV_U4:
                case OP_MOVE:
-               case OP_SETREG:
                        ins->opcode = OP_MOVE;
                        /* 
                         * OP_MOVE reg, reg 
                         */
                        if (ins->dreg == ins->sreg1) {
-                               if (last_ins)
-                                       last_ins->next = ins->next;                             
-                               ins = ins->next;
+                               MONO_DELETE_INS (bb, ins);
                                continue;
                        }
                        /* 
@@ -1404,8 +1975,7 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && last_ins->opcode == OP_MOVE &&
                            ins->sreg1 == last_ins->dreg &&
                            ins->dreg == last_ins->sreg1) {
-                               last_ins->next = ins->next;                             
-                               ins = ins->next;                                
+                               MONO_DELETE_INS (bb, ins);
                                continue;
                        }
                        break;
@@ -1416,6 +1986,58 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
        bb->last_ins = last_ins;
 }
 
+void
+mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
+{
+       g_assert (cfg->new_ir);
+
+       switch (ins->opcode) {
+       case OP_ICONV_TO_R_UN: {
+               static const guint64 adjust_val = 0x4330000000000000ULL;
+               int msw_reg = mono_alloc_ireg (cfg);
+               int adj_reg = mono_alloc_freg (cfg);
+               int tmp_reg = mono_alloc_freg (cfg);
+               MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
+               MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
+               MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
+               ins->opcode = OP_NOP;
+               break;
+       }
+       case OP_ICONV_TO_R4:
+       case OP_ICONV_TO_R8: {
+               /* FIXME: change precision for CEE_CONV_R4 */
+               static const guint64 adjust_val = 0x4330000080000000ULL;
+               int msw_reg = mono_alloc_ireg (cfg);
+               int xored = mono_alloc_ireg (cfg);
+               int adj_reg = mono_alloc_freg (cfg);
+               int tmp_reg = mono_alloc_freg (cfg);
+               MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
+               MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
+               MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
+               if (ins->opcode == OP_ICONV_TO_R4)
+                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
+               ins->opcode = OP_NOP;
+               break;
+       }
+       case OP_CKFINITE: {
+               int msw_reg = mono_alloc_ireg (cfg);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
+               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
+               ins->opcode = OP_NOP;
+               break;
+       }
+       }
+}
+
 /* 
  * the branch_b0_table should maintain the order of these
  * opcodes.
@@ -1460,23 +2082,9 @@ branch_b1_table [] = {
        PPC_BR_LT 
 };
 
-static void
-insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
-{
-       if (ins == NULL) {
-               ins = bb->code;
-               bb->code = to_insert;
-               to_insert->next = ins;
-       } else {
-               to_insert->next = ins->next;
-               ins->next = to_insert;
-       }
-}
-
-#define NEW_INS(cfg,dest,op) do {       \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = (op);  \
-               insert_after_ins (bb, last_ins, (dest)); \
+#define NEW_INS(cfg,dest,op) do {                                      \
+               MONO_INST_NEW((cfg), (dest), (op));                     \
+               mono_bblock_insert_after_ins (bb, last_ins, (dest));    \
        } while (0)
 
 static int
@@ -1484,27 +2092,29 @@ map_to_reg_reg_op (int op)
 {
        switch (op) {
        case OP_ADD_IMM:
-               return CEE_ADD;
+               return OP_IADD;
        case OP_SUB_IMM:
-               return CEE_SUB;
+               return OP_ISUB;
        case OP_AND_IMM:
-               return CEE_AND;
+               return OP_IAND;
        case OP_COMPARE_IMM:
                return OP_COMPARE;
+       case OP_ICOMPARE_IMM:
+               return OP_ICOMPARE;
        case OP_ADDCC_IMM:
-               return OP_ADDCC;
+               return OP_IADDCC;
        case OP_ADC_IMM:
-               return OP_ADC;
+               return OP_IADC;
        case OP_SUBCC_IMM:
-               return OP_SUBCC;
+               return OP_ISUBCC;
        case OP_SBB_IMM:
-               return OP_SBB;
+               return OP_ISBB;
        case OP_OR_IMM:
-               return CEE_OR;
+               return OP_IOR;
        case OP_XOR_IMM:
-               return CEE_XOR;
+               return OP_IXOR;
        case OP_MUL_IMM:
-               return CEE_MUL;
+               return OP_IMUL;
        case OP_LOAD_MEMBASE:
                return OP_LOAD_MEMINDEX;
        case OP_LOADI4_MEMBASE:
@@ -1544,19 +2154,23 @@ map_to_reg_reg_op (int op)
        case OP_STOREI4_MEMBASE_IMM:
                return OP_STOREI4_MEMBASE_REG;
        }
-       g_assert_not_reached ();
+       return mono_op_imm_to_op (op);
 }
 
+//#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
+
 #define compare_opcode_is_unsigned(opcode) \
                (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
+               (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) ||  \
                ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
-               ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
+               ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) ||   \
+               ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
 /*
  * Remove from the instruction list the instructions that can't be
  * represented with very simple instructions with no register
  * requirements.
  */
-static void
+void
 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
 {
        MonoInst *ins, *next, *temp, *last_ins = NULL;
@@ -1566,20 +2180,60 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
        if (bb->max_vreg > cfg->rs->next_vreg)
                cfg->rs->next_vreg = bb->max_vreg;
 
-       ins = bb->code;
-       while (ins) {
+       MONO_BB_FOR_EACH_INS (bb, ins) {
 loop_start:
                switch (ins->opcode) {
+               case OP_IDIV_UN_IMM:
+               case OP_IDIV_IMM:
+               case OP_IREM_IMM:
+               case OP_IREM_UN_IMM:
+                       NEW_INS (cfg, temp, OP_ICONST);
+                       temp->inst_c0 = ins->inst_imm;
+                       temp->dreg = mono_regstate_next_int (cfg->rs);
+                       ins->sreg2 = temp->dreg;
+                       if (ins->opcode == OP_IDIV_IMM)
+                               ins->opcode = OP_IDIV;
+                       else if (ins->opcode == OP_IREM_IMM)
+                               ins->opcode = OP_IREM;
+                       else if (ins->opcode == OP_IDIV_UN_IMM)
+                               ins->opcode = OP_IDIV_UN;
+                       else if (ins->opcode == OP_IREM_UN_IMM)
+                               ins->opcode = OP_IREM_UN;
+                       last_ins = temp;
+                       /* handle rem separately */
+                       goto loop_start;
+               case OP_IREM:
+               case OP_IREM_UN: {
+                       MonoInst *mul;
+                       /* we change a rem dest, src1, src2 to
+                        * div temp1, src1, src2
+                        * mul temp2, temp1, src2
+                        * sub dest, src1, temp2
+                        */
+                       NEW_INS (cfg, mul, OP_IMUL);
+                       NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
+                       temp->sreg1 = ins->sreg1;
+                       temp->sreg2 = ins->sreg2;
+                       temp->dreg = mono_regstate_next_int (cfg->rs);
+                       mul->sreg1 = temp->dreg;
+                       mul->sreg2 = ins->sreg2;
+                       mul->dreg = mono_regstate_next_int (cfg->rs);
+                       ins->opcode = OP_ISUB;
+                       ins->sreg2 = mul->dreg;
+                       break;
+               }
+               case OP_IADD_IMM:
                case OP_ADD_IMM:
                case OP_ADDCC_IMM:
                        if (!ppc_is_imm16 (ins->inst_imm)) {
-                               NEW_INS (cfg, 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);
                        }
                        break;
+               case OP_ISUB_IMM:
                case OP_SUB_IMM:
                        if (!ppc_is_imm16 (-ins->inst_imm)) {
                                NEW_INS (cfg, temp, OP_ICONST);
@@ -1589,6 +2243,9 @@ loop_start:
                                ins->opcode = map_to_reg_reg_op (ins->opcode);
                        }
                        break;
+               case OP_IAND_IMM:
+               case OP_IOR_IMM:
+               case OP_IXOR_IMM:
                case OP_AND_IMM:
                case OP_OR_IMM:
                case OP_XOR_IMM:
@@ -1600,6 +2257,8 @@ loop_start:
                                ins->opcode = map_to_reg_reg_op (ins->opcode);
                        }
                        break;
+               case OP_ISBB_IMM:
+               case OP_IADC_IMM:
                case OP_SBB_IMM:
                case OP_SUBCC_IMM:
                case OP_ADC_IMM:
@@ -1610,7 +2269,15 @@ loop_start:
                        ins->opcode = map_to_reg_reg_op (ins->opcode);
                        break;
                case OP_COMPARE_IMM:
-                       if (compare_opcode_is_unsigned (ins->next->opcode)) {
+               case OP_ICOMPARE_IMM:
+                       next = ins->next;
+                       /* Branch opts can eliminate the branch */
+                       if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
+                               ins->opcode = OP_NOP;
+                               break;
+                       }
+                       g_assert(next);
+                       if (compare_opcode_is_unsigned (next->opcode)) {
                                if (!ppc_is_uimm16 (ins->inst_imm)) {
                                        NEW_INS (cfg, temp, OP_ICONST);
                                        temp->inst_c0 = ins->inst_imm;
@@ -1628,6 +2295,7 @@ loop_start:
                                }
                        }
                        break;
+               case OP_IMUL_IMM:
                case OP_MUL_IMM:
                        if (ins->inst_imm == 1) {
                                ins->opcode = OP_MOVE;
@@ -1652,6 +2320,13 @@ loop_start:
                                ins->opcode = map_to_reg_reg_op (ins->opcode);
                        }
                        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:
@@ -1691,24 +2366,27 @@ loop_start:
                        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_R8CONST:
+               case OP_R4CONST:
+                       NEW_INS (cfg, temp, OP_ICONST);
+                       temp->inst_c0 = (guint32)ins->inst_p0;
+                       temp->dreg = mono_regstate_next_int (cfg->rs);
+                       ins->inst_basereg = temp->dreg;
+                       ins->inst_offset = 0;
+                       ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
+                       last_ins = temp;
+                       /* make it handle the possibly big ins->inst_offset
+                        * later optimize to use lis + load_membase
+                        */
+                       goto loop_start;
                }
                last_ins = ins;
-               ins = ins->next;
        }
        bb->last_ins = last_ins;
        bb->max_vreg = cfg->rs->next_vreg;
        
 }
 
-void
-mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
-{
-       if (!bb->code)
-               return;
-       mono_arch_lowering_pass (cfg, bb);
-       mono_local_regalloc (cfg, bb);
-}
-
 static guchar*
 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
 {
@@ -1730,51 +2408,9 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
        return code;
 }
 
-static unsigned char*
-mono_emit_stack_alloc (guchar *code, MonoInst* tree)
-{
-#if 0
-       int sreg = tree->sreg1;
-       x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
-       if (tree->flags & MONO_INST_INIT) {
-               int offset = 0;
-               if (tree->dreg != X86_EAX && sreg != X86_EAX) {
-                       x86_push_reg (code, X86_EAX);
-                       offset += 4;
-               }
-               if (tree->dreg != X86_ECX && sreg != X86_ECX) {
-                       x86_push_reg (code, X86_ECX);
-                       offset += 4;
-               }
-               if (tree->dreg != X86_EDI && sreg != X86_EDI) {
-                       x86_push_reg (code, X86_EDI);
-                       offset += 4;
-               }
-               
-               x86_shift_reg_imm (code, X86_SHR, sreg, 2);
-               if (sreg != X86_ECX)
-                       x86_mov_reg_reg (code, X86_ECX, sreg, 4);
-               x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
-                               
-               x86_lea_membase (code, X86_EDI, X86_ESP, offset);
-               x86_cld (code);
-               x86_prefix (code, X86_REP_PREFIX);
-               x86_stosl (code);
-               
-               if (tree->dreg != X86_EDI && sreg != X86_EDI)
-                       x86_pop_reg (code, X86_EDI);
-               if (tree->dreg != X86_ECX && sreg != X86_ECX)
-                       x86_pop_reg (code, X86_ECX);
-               if (tree->dreg != X86_EAX && sreg != X86_EAX)
-                       x86_pop_reg (code, X86_EAX);
-       }
-#endif
-       return code;
-}
-
 typedef struct {
        guchar *code;
-       guchar *target;
+       const guchar *target;
        int absolute;
        int found;
 } PatchData;
@@ -1789,7 +2425,7 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
        guint32 *endthunks = (guint32*)(code + bsize);
        guint32 load [2];
        guchar *templ;
-       int i, count = 0;
+       int count = 0;
        int difflow, diffhigh;
 
        /* always ensure a call from pdata->code can reach to the thunks without further thunks */
@@ -1847,7 +2483,7 @@ search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
 }
 
 static void
-handle_thunk (int absolute, guchar *code, guchar *target) {
+handle_thunk (int absolute, guchar *code, const guchar *target) {
        MonoDomain *domain = mono_domain_get ();
        PatchData pdata;
 
@@ -1872,7 +2508,7 @@ handle_thunk (int absolute, guchar *code, guchar *target) {
 }
 
 void
-ppc_patch (guchar *code, guchar *target)
+ppc_patch (guchar *code, const guchar *target)
 {
        guint32 ins = *(guint32*)code;
        guint32 prim = ins >> 26;
@@ -1964,10 +2600,144 @@ ppc_patch (guchar *code, guchar *target)
 //     g_print ("patched with 0x%08x\n", ins);
 }
 
+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:
+               if (ins->dreg != ppc_f1)
+                       ppc_fmr (code, ins->dreg, ppc_f1);
+               break;
+       }
+
+       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;
+       int struct_index = 0;
+
+       /* 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 (ppc_is_imm16 (inst->inst_offset));
+               ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+       }
+       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+               ArgInfo *ainfo = cinfo->args + i;
+               inst = cfg->args [pos];
+
+               g_assert (inst->opcode != OP_REGVAR);
+               g_assert (ppc_is_imm16 (inst->inst_offset));
+
+               switch (ainfo->regtype) {
+               case RegTypeGeneral:
+                       switch (ainfo->size) {
+                               case 1:
+                                       ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+                                       break;
+                               case 2:
+                                       ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+                                       break;
+                               default:
+                                       ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+                                       break;
+                       }
+                       break;
+
+               case RegTypeFP:
+                       switch (ainfo->size) {
+                               case 4:
+                                       ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+                                       break;
+                               case 8:
+                                       ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+                                       break;
+                               default:
+                                       g_assert_not_reached ();
+                       }
+                       break;
+
+               case RegTypeBase:
+                       /* FIXME: */
+                       NOT_IMPLEMENTED;
+
+               case RegTypeStructByVal: {
+                       guint32 size = 0;
+
+                       /* FIXME: */
+                       if (ainfo->vtsize)
+                               NOT_IMPLEMENTED;
+#ifdef __APPLE__
+                       /*
+                        * Darwin pinvokes needs some special handling
+                        * for 1 and 2 byte arguments
+                        */
+                       if (method->signature->pinvoke)
+                               size = mono_class_native_size (inst->klass, NULL);
+                       if (size == 1 || size == 2) {
+                               /* FIXME: */
+                               NOT_IMPLEMENTED;
+                       } else
+#endif
+                               for (i = 0; i < ainfo->size; ++i) {
+                                       ppc_lwz (code, ainfo->reg  + i,
+                                               inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
+                               }
+                       break;
+               }
+
+               case RegTypeStructByAddr: {
+                       MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
+
+                       g_assert (ppc_is_imm16 (addr->inst_offset));
+                       g_assert (!ainfo->offset);
+                       ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
+
+                       struct_index++;
+                       break;
+               }
+
+               default:
+                       g_assert_not_reached ();
+               }
+
+               pos ++;
+       }
+
+       g_free (cinfo);
+
+       return code;
+}
+
 void
 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 {
-       MonoInst *ins;
+       MonoInst *ins, *next;
        MonoCallInst *call;
        guint offset;
        guint8 *code = cfg->native_code + cfg->code_len;
@@ -1975,9 +2745,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
        guint last_offset = 0;
        int max_len, cpos;
 
-       if (cfg->opt & MONO_OPT_PEEPHOLE)
-               peephole_pass (cfg, bb);
-
        /* we don't align basic blocks of loops on ppc */
 
        if (cfg->verbose_level > 2)
@@ -1996,8 +2763,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                //x86_inc_mem (code, &cov->data [bb->dfn].count); 
        }
 
-       ins = bb->code;
-       while (ins) {
+       MONO_BB_FOR_EACH_INS (bb, ins) {
                offset = code - cfg->native_code;
 
                max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
@@ -2012,6 +2778,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                mono_debug_record_line_number (cfg, ins, offset);
 
                switch (ins->opcode) {
+               case OP_RELAXED_NOP:
+               case OP_NOP:
+               case OP_DUMMY_USE:
+               case OP_DUMMY_STORE:
+               case OP_NOT_REACHED:
+               case OP_NOT_NULL:
+                       break;
                case OP_TLS_GET:
                        emit_tls_access (code, ins->dreg, ins->inst_offset);
                        break;
@@ -2032,14 +2805,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_STOREI2_MEMBASE_REG:
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_STORE_MEMBASE_REG:
@@ -2047,7 +2822,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_STOREI1_MEMINDEX:
@@ -2060,12 +2836,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_STOREI4_MEMINDEX:
                        ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
                        break;
-               case CEE_LDIND_I:
-               case CEE_LDIND_I4:
-               case CEE_LDIND_U4:
-                       g_assert_not_reached ();
-                       //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
-                       break;
                case OP_LOADU4_MEM:
                        g_assert_not_reached ();
                        break;
@@ -2075,7 +2845,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
                        }
                        break;
                case OP_LOADI1_MEMBASE:
@@ -2083,7 +2854,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
                        }
                        if (ins->opcode == OP_LOADI1_MEMBASE)
                                ppc_extsb (code, ins->dreg, ins->dreg);
@@ -2092,14 +2864,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
                        }
                        break;
                case OP_LOADI2_MEMBASE:
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
                        }
                        break;
                case OP_LOAD_MEMINDEX:
@@ -2120,26 +2894,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
                        ppc_extsb (code, ins->dreg, ins->dreg);
                        break;
-               case CEE_CONV_I1:
+               case OP_ICONV_TO_I1:
                        ppc_extsb (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_CONV_I2:
+               case OP_ICONV_TO_I2:
                        ppc_extsh (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_CONV_U1:
+               case OP_ICONV_TO_U1:
                        ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
                        break;
-               case CEE_CONV_U2:
+               case OP_ICONV_TO_U2:
                        ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
                        break;
                case OP_COMPARE:
-                       if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
+               case OP_ICOMPARE:
+                       next = ins->next;
+                       if (next && compare_opcode_is_unsigned (next->opcode))
                                ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
                        else
                                ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
                        break;
                case OP_COMPARE_IMM:
-                       if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
+               case OP_ICOMPARE_IMM:
+                       next = ins->next;
+                       if (next && compare_opcode_is_unsigned (next->opcode)) {
                                if (ppc_is_uimm16 (ins->inst_imm)) {
                                        ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
                                } else {
@@ -2153,16 +2931,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                }
                        }
                        break;
-               case CEE_BREAK:
+               case OP_BREAK:
                        ppc_break (code);
                        break;
                case OP_ADDCC:
+               case OP_IADDCC:
                        ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
-               case CEE_ADD:
+               case OP_IADD:
                        ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ADC:
+               case OP_IADC:
                        ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ADDCC_IMM:
@@ -2173,13 +2953,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        break;
                case OP_ADD_IMM:
+               case OP_IADD_IMM:
                        if (ppc_is_imm16 (ins->inst_imm)) {
                                ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        } else {
                                g_assert_not_reached ();
                        }
                        break;
-               case CEE_ADD_OVF:
+               case OP_IADD_OVF:
                        /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
                         */
                        ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
@@ -2187,7 +2968,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
                        break;
-               case CEE_ADD_OVF_UN:
+               case OP_IADD_OVF_UN:
                        /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
                         */
                        ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
@@ -2195,7 +2976,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
                        break;
-               case CEE_SUB_OVF:
+               case OP_ISUB_OVF:
                        /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
                         */
                        ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
@@ -2203,7 +2984,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
                        break;
-               case CEE_SUB_OVF_UN:
+               case OP_ISUB_OVF_UN:
                        /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
                         */
                        ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
@@ -2244,15 +3025,18 @@ 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:
                        ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
                        break;
-               case CEE_SUB:
+               case OP_ISUB:
                        ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
                        break;
                case OP_SBB:
+               case OP_ISBB:
                        ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
                        break;
                case OP_SUB_IMM:
+               case OP_ISUB_IMM:
                        // we add the negated value
                        if (ppc_is_imm16 (-ins->inst_imm))
                                ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
@@ -2267,11 +3051,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_PPC_SUBFZE:
                        ppc_subfze (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_AND:
+               case OP_IAND:
                        /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
                        ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
                        break;
                case OP_AND_IMM:
+               case OP_IAND_IMM:
                        if (!(ins->inst_imm & 0xffff0000)) {
                                ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
                        } else if (!(ins->inst_imm & 0xffff)) {
@@ -2280,15 +3065,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                g_assert_not_reached ();
                        }
                        break;
-               case CEE_DIV: {
-                       guint32 *divisor_is_m1;
+               case OP_IDIV: {
+                       guint8 *divisor_is_m1;
                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
                          */
                        ppc_cmpi (code, 0, 0, ins->sreg2, -1);
                        divisor_is_m1 = code;
                        ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
-                       ppc_lis (code, ppc_r11, 0x8000);
-                       ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
+                       ppc_lis (code, ppc_r0, 0x8000);
+                       ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
                        ppc_patch (divisor_is_m1, code);
                         /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
@@ -2299,55 +3084,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
                        break;
                }
-               case CEE_DIV_UN:
+               case OP_IDIV_UN:
                        ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
                        ppc_mfspr (code, ppc_r0, ppc_xer);
                        ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
                        break;
                case OP_DIV_IMM:
-                       g_assert_not_reached ();
-#if 0
-                       ppc_load (code, ppc_r11, ins->inst_imm);
-                       ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
-                       ppc_mfspr (code, ppc_r0, ppc_xer);
-                       ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
-                       /* FIXME: use OverflowException for 0x80000000/-1 */
-                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
-                       break;
-#endif
-               case CEE_REM: {
-                       guint32 *divisor_is_m1;
-                       ppc_cmpi (code, 0, 0, ins->sreg2, -1);
-                       divisor_is_m1 = code;
-                       ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
-                       ppc_lis (code, ppc_r11, 0x8000);
-                       ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
-                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
-                       ppc_patch (divisor_is_m1, code);
-                       ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
-                       ppc_mfspr (code, ppc_r0, ppc_xer);
-                       ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
-                       /* FIXME: use OverflowException for 0x80000000/-1 */
-                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
-                       ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
-                       ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
-                       break;
-               }
-               case CEE_REM_UN:
-                       ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
-                       ppc_mfspr (code, ppc_r0, ppc_xer);
-                       ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
-                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
-                       ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
-                       ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
-                       break;
+               case OP_IREM:
+               case OP_IREM_UN:
                case OP_REM_IMM:
                        g_assert_not_reached ();
-               case CEE_OR:
+               case OP_IOR:
                        ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_OR_IMM:
+               case OP_IOR_IMM:
                        if (!(ins->inst_imm & 0xffff0000)) {
                                ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
                        } else if (!(ins->inst_imm & 0xffff)) {
@@ -2356,9 +3108,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                g_assert_not_reached ();
                        }
                        break;
-               case CEE_XOR:
+               case OP_IXOR:
                        ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_IXOR_IMM:
                case OP_XOR_IMM:
                        if (!(ins->inst_imm & 0xffff0000)) {
                                ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
@@ -2368,33 +3121,40 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                g_assert_not_reached ();
                        }
                        break;
-               case CEE_SHL:
+               case OP_ISHL:
                        ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
                        break;
                case OP_SHL_IMM:
+               case OP_ISHL_IMM:
                        ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
                        break;
-               case CEE_SHR:
+               case OP_ISHR:
                        ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_SHR_IMM:
+               case OP_ISHR_IMM:
                        ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
                        break;
                case OP_SHR_UN_IMM:
-                       ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
+               case OP_ISHR_UN_IMM:
+                       if (ins->inst_imm)
+                               ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
+                       else
+                               ppc_mr (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_SHR_UN:
+               case OP_ISHR_UN:
                        ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
-               case CEE_NOT:
+               case OP_INOT:
                        ppc_not (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_NEG:
+               case OP_INEG:
                        ppc_neg (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_MUL:
+               case OP_IMUL:
                        ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
+               case OP_IMUL_IMM:
                case OP_MUL_IMM:
                        if (ppc_is_imm16 (ins->inst_imm)) {
                            ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
@@ -2402,7 +3162,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                            g_assert_not_reached ();
                        }
                        break;
-               case CEE_MUL_OVF:
+               case OP_IMUL_OVF:
                        /* we annot use mcrxr, since it's not implemented on some processors 
                         * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
                         */
@@ -2411,7 +3171,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
                        EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
                        break;
-               case CEE_MUL_OVF_UN:
+               case OP_IMUL_OVF_UN:
                        /* we first multiply to get the high word and compare to 0
                         * to set the flags, then the result is discarded and then 
                         * we multiply to get the lower * bits result
@@ -2422,7 +3182,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_ICONST:
-               case OP_SETREGIMM:
                        ppc_load (code, ins->dreg, ins->inst_c0);
                        break;
                case OP_AOTCONST:
@@ -2430,10 +3189,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_lis (code, ins->dreg, 0);
                        ppc_ori (code, ins->dreg, ins->dreg, 0);
                        break;
-               case CEE_CONV_I4:
-               case CEE_CONV_U4:
+               case OP_ICONV_TO_I4:
+               case OP_ICONV_TO_U4:
                case OP_MOVE:
-               case OP_SETREG:
                        ppc_mr (code, ins->dreg, ins->sreg1);
                        break;
                case OP_SETLRET: {
@@ -2448,20 +3206,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ppc_mr (code, ppc_r4, saved);
                        break;
                }
-               case OP_SETFREG:
                case OP_FMOVE:
                        ppc_fmr (code, ins->dreg, ins->sreg1);
                        break;
                case OP_FCONV_TO_R4:
                        ppc_frsp (code, ins->dreg, ins->sreg1);
                        break;
-               case CEE_JMP: {
+               case OP_JMP: {
                        int i, pos = 0;
                        
                        /*
                         * Keep in sync with mono_arch_emit_epilog
                         */
                        g_assert (!cfg->method->save_lmf);
+                       /*
+                        * Note: we can use ppc_r11 here because it is dead anyway:
+                        * we're leaving the method.
+                        */
                        if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
                                if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
                                        ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
@@ -2471,6 +3232,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                }
                                ppc_mtlr (code, ppc_r0);
                        }
+
+                       code = emit_load_volatile_arguments (cfg, code);
+
                        if (ppc_is_imm16 (cfg->stack_usage)) {
                                ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
                        } else {
@@ -2503,19 +3267,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_ARGLIST: {
                        if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
-                               ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
+                               ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
                        } else {
-                               ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
-                               ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
+                               ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
+                               ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
                        }
-                       ppc_stw (code, ppc_r11, 0, ins->sreg1);
+                       ppc_stw (code, ppc_r0, 0, ins->sreg1);
                        break;
                }
                case OP_FCALL:
                case OP_LCALL:
                case OP_VCALL:
+               case OP_VCALL2:
                case OP_VOIDCALL:
-               case CEE_CALL:
+               case OP_CALL:
                        call = (MonoCallInst*)ins;
                        if (ins->flags & MONO_INST_HAS_METHOD)
                                mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
@@ -2529,29 +3294,37 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        } else {
                                ppc_bl (code, 0);
                        }
+                       /* FIXME: this should be handled somewhere else in the new jit */
+                       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:
                        ppc_mtlr (code, ins->sreg1);
                        ppc_blrl (code);
+                       /* FIXME: this should be handled somewhere else in the new jit */
+                       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:
                        ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
                        ppc_mtlr (code, ppc_r0);
                        ppc_blrl (code);
+                       /* FIXME: this should be handled somewhere else in the new jit */
+                       code = emit_move_return_value (cfg, ins, code);
                        break;
                case OP_OUTARG:
                        g_assert_not_reached ();
                        break;
                case OP_LOCALLOC: {
-                       guint32 * zero_loop_jump, * zero_loop_start;
+                       guint8 * zero_loop_jump, * zero_loop_start;
                        /* keep alignment */
                        int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
                        int area_offset = alloca_waste;
@@ -2560,8 +3333,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
                        /* use ctr to store the number of words to 0 if needed */
                        if (ins->flags & MONO_INST_INIT) {
-                               /* we zero 4 bytes at a time */
-                               ppc_addi (code, ppc_r0, ins->sreg1, 3);
+                               /* we zero 4 bytes at a time:
+                                * we add 7 instead of 3 so that we set the counter to
+                                * at least 1, otherwise the bdnz instruction will make
+                                * it negative and iterate billions of times.
+                                */
+                               ppc_addi (code, ppc_r0, ins->sreg1, 7);
                                ppc_srawi (code, ppc_r0, ppc_r0, 2);
                                ppc_mtctr (code, ppc_r0);
                        }
@@ -2571,7 +3348,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        
                        if (ins->flags & MONO_INST_INIT) {
                                /* adjust the dest reg by -4 so we can use stwu */
-                               ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
+                               /* we actually adjust -8 because we let the loop
+                                * run at least once
+                                */
+                               ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
                                ppc_li (code, ppc_r11, 0);
                                zero_loop_start = code;
                                ppc_stwu (code, ppc_r11, 4, ins->dreg);
@@ -2582,10 +3362,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_addi (code, ins->dreg, ppc_sp, area_offset);
                        break;
                }
-               case CEE_RET:
-                       ppc_blr (code);
-                       break;
-               case CEE_THROW: {
+               case OP_THROW: {
                        //ppc_break (code);
                        ppc_mr (code, ppc_r3, ins->sreg1);
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
@@ -2615,32 +3392,38 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        break;
                }
-               case OP_START_HANDLER:
+               case OP_START_HANDLER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
                        ppc_mflr (code, ppc_r0);
-                       if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
-                               ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+                       if (ppc_is_imm16 (spvar->inst_offset)) {
+                               ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
                        } else {
-                               ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
-                               ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
+                               ppc_load (code, ppc_r11, spvar->inst_offset);
+                               ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
                        }
                        break;
-               case OP_ENDFILTER:
+               }
+               case OP_ENDFILTER: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
                        if (ins->sreg1 != ppc_r3)
                                ppc_mr (code, ppc_r3, ins->sreg1);
-                       if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
-                               ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+                       if (ppc_is_imm16 (spvar->inst_offset)) {
+                               ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
                        } else {
-                               ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
-                               ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
+                               ppc_load (code, ppc_r11, spvar->inst_offset);
+                               ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
                        }
                        ppc_mtlr (code, ppc_r0);
                        ppc_blr (code);
                        break;
-               case CEE_ENDFINALLY:
-                       ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+               }
+               case OP_ENDFINALLY: {
+                       MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+                       ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
                        ppc_mtlr (code, ppc_r0);
                        ppc_blr (code);
                        break;
+               }
                case OP_CALL_HANDLER: 
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
                        ppc_bl (code, 0);
@@ -2648,10 +3431,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_LABEL:
                        ins->inst_c0 = code - cfg->native_code;
                        break;
-               case CEE_BR:
-                       //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
-                       //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
-                       //break;
+               case OP_BR:
                        if (ins->flags & MONO_INST_BRLABEL) {
                                /*if (ins->inst_i0->inst_c0) {
                                        ppc_b (code, 0);
@@ -2675,18 +3455,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_bcctr (code, PPC_BR_ALWAYS, 0);
                        break;
                case OP_CEQ:
+               case OP_ICEQ:
                        ppc_li (code, ins->dreg, 0);
                        ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
                        ppc_li (code, ins->dreg, 1);
                        break;
                case OP_CLT:
                case OP_CLT_UN:
+               case OP_ICLT:
+               case OP_ICLT_UN:
                        ppc_li (code, ins->dreg, 1);
                        ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
                        ppc_li (code, ins->dreg, 0);
                        break;
                case OP_CGT:
                case OP_CGT_UN:
+               case OP_ICGT:
+               case OP_ICGT_UN:
                        ppc_li (code, ins->dreg, 1);
                        ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
                        ppc_li (code, ins->dreg, 0);
@@ -2703,6 +3488,18 @@ 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:
                        /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
                         */
@@ -2718,40 +3515,37 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_COND_EXC_NO:
                        g_assert_not_reached ();
                        break;
-               case CEE_BEQ:
-               case CEE_BNE_UN:
-               case CEE_BLT:
-               case CEE_BLT_UN:
-               case CEE_BGT:
-               case CEE_BGT_UN:
-               case CEE_BGE:
-               case CEE_BGE_UN:
-               case CEE_BLE:
-               case CEE_BLE_UN:
-                       EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
+               case OP_IBEQ:
+               case OP_IBNE_UN:
+               case OP_IBLT:
+               case OP_IBLT_UN:
+               case OP_IBGT:
+               case OP_IBGT_UN:
+               case OP_IBGE:
+               case OP_IBGE_UN:
+               case OP_IBLE:
+               case OP_IBLE_UN:
+                       EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
                        break;
 
                /* floating point opcodes */
                case OP_R8CONST:
-                       ppc_load (code, ppc_r11, ins->inst_p0);
-                       ppc_lfd (code, ins->dreg, 0, ppc_r11);
-                       break;
                case OP_R4CONST:
-                       ppc_load (code, ppc_r11, ins->inst_p0);
-                       ppc_lfs (code, ins->dreg, 0, ppc_r11);
-                       break;
+                       g_assert_not_reached ();
                case OP_STORER8_MEMBASE_REG:
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_LOADR8_MEMBASE:
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_STORER4_MEMBASE_REG:
@@ -2759,14 +3553,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_LOADR4_MEMBASE:
                        if (ppc_is_imm16 (ins->inst_offset)) {
                                ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
                        } else {
-                               g_assert_not_reached ();
+                               ppc_load (code, ppc_r0, ins->inst_offset);
+                               ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
                        }
                        break;
                case OP_LOADR4_MEMINDEX:
@@ -2782,31 +3578,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_STORER8_MEMINDEX:
                        ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
                        break;
-               case CEE_CONV_R_UN: {
-                       static const guint64 adjust_val = 0x4330000000000000ULL;
-                       ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
-                       ppc_stw (code, ppc_r0, -8, ppc_sp);
-                       ppc_stw (code, ins->sreg1, -4, ppc_sp);
-                       ppc_load (code, ppc_r11, &adjust_val);
-                       ppc_lfd (code, ins->dreg, -8, ppc_sp);
-                       ppc_lfd (code, ppc_f0, 0, ppc_r11);
-                       ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
-                       break;
-               }
+               case CEE_CONV_R_UN:
                case CEE_CONV_R4: /* FIXME: change precision */
-               case CEE_CONV_R8: {
-                       static const guint64 adjust_val = 0x4330000080000000ULL;
-                       // addis is special for ppc_r0
-                       ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
-                       ppc_stw (code, ppc_r0, -8, ppc_sp);
-                       ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
-                       ppc_stw (code, ppc_r11, -4, ppc_sp);
-                       ppc_lfd (code, ins->dreg, -8, ppc_sp);
-                       ppc_load (code, ppc_r11, &adjust_val);
-                       ppc_lfd (code, ppc_f0, 0, ppc_r11);
-                       ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
-                       break;
-               }
+               case CEE_CONV_R8:
+                       g_assert_not_reached ();
                case OP_FCONV_TO_I1:
                        code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
                        break;
@@ -2836,8 +3611,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert_not_reached ();
                        /* Implemented as helper calls */
                        break;
+               case OP_LCONV_TO_OVF_I4_2:
                case OP_LCONV_TO_OVF_I: {
-                       guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
+                       guint8 *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;
@@ -2884,7 +3660,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert_not_reached ();
                        break;
                case OP_FCOMPARE:
-                       ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
+                       ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
                        break;
                case OP_FCEQ:
                        ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
@@ -2925,6 +3701,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
                        break;
                case OP_FBLT:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
                        break;
                case OP_FBLT_UN:
@@ -2932,6 +3709,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
                        break;
                case OP_FBGT:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
                        break;
                case OP_FBGT_UN:
@@ -2939,25 +3717,31 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
                        break;
                case OP_FBGE:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
                        break;
                case OP_FBGE_UN:
                        EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
                        break;
                case OP_FBLE:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
                        break;
                case OP_FBLE_UN:
                        EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
                        break;
-               case CEE_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);
+               case OP_CKFINITE:
+                       g_assert_not_reached ();
+               case OP_CHECK_FINITE: {
+                       ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
+                       ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
+                       ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
                        EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
                        break;
+               case OP_JUMP_TABLE:
+                       mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+                       ppc_load (code, ins->dreg, 0x0f0f0f0f);
+                       break;
                }
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
@@ -2974,8 +3758,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                last_ins = ins;
                last_offset = offset;
-               
-               ins = ins->next;
        }
 
        cfg->code_len = code - cfg->native_code;
@@ -2999,7 +3781,7 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
 
        for (patch_info = ji; patch_info; patch_info = patch_info->next) {
                unsigned char *ip = patch_info->ip.i + code;
-               const unsigned char *target;
+               unsigned char *target;
 
                target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
 
@@ -3087,6 +3869,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        CallInfo *cinfo;
        int tracing = 0;
        int lmf_offset = 0;
+       int tailcall_struct_index;
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                tracing = 1;
@@ -3152,16 +3935,14 @@ mono_arch_emit_prolog (MonoCompile *cfg)
         */
        max_offset = 0;
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins = bb->code;
+               MonoInst *ins;
                bb->max_offset = max_offset;
 
                if (cfg->prof_options & MONO_PROFILE_COVERAGE)
                        max_offset += 6; 
 
-               while (ins) {
+               MONO_BB_FOR_EACH_INS (bb, ins)
                        max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
-                       ins = ins->next;
-               }
        }
 
        /* load arguments allocated to register from the stack */
@@ -3171,7 +3952,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                ArgInfo *ainfo = &cinfo->ret;
-               inst = cfg->ret;
+
+               if (cfg->new_ir)
+                       inst = cfg->vret_addr;
+               else
+                       inst = cfg->ret;
+               g_assert (inst);
+
                if (ppc_is_imm16 (inst->inst_offset)) {
                        ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
                } else {
@@ -3179,9 +3966,11 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
                }
        }
+
+       tailcall_struct_index = 0;
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                ArgInfo *ainfo = cinfo->args + i;
-               inst = cfg->varinfo [pos];
+               inst = cfg->args [pos];
                
                if (cfg->verbose_level > 2)
                        g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
@@ -3293,19 +4082,23 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                int size = 0;
                                g_assert (ppc_is_imm16 (inst->inst_offset));
                                g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
-                               if (mono_class_from_mono_type (inst->inst_vtype))
+                               /* FIXME: what if there is no class? */
+                               if (sig->pinvoke && 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) {
-/*
-Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
-register.  Should this case include linux/ppc?
-*/
 #if __APPLE__
+                                       /*
+                                        * Darwin handles 1 and 2 byte
+                                        * structs specially by
+                                        * loading h/b into the arg
+                                        * register.  Only done for
+                                        * pinvokes.
+                                        */
                                        if (size == 2)
                                                ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
                                        else if (size == 1)
                                                ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
-                                       else 
+                                       else
 #endif
                                                ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
                                        soffset += sizeof (gpointer);
@@ -3314,8 +4107,15 @@ register.  Should this case include linux/ppc?
                                if (ainfo->vtsize) {
                                        /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
                                        ppc_lwz (code, ppc_r11, 0, ppc_sp);
-                                       /* FIXME: handle overrun! with struct sizes not multiple of 4 */
-                                       code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
+                                       if ((size & 3) != 0) {
+                                               code = emit_memcpy (code, size - soffset,
+                                                       inst->inst_basereg, doffset,
+                                                       ppc_r11, ainfo->offset + soffset);
+                                       } else {
+                                               code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
+                                                       inst->inst_basereg, doffset,
+                                                       ppc_r11, ainfo->offset + soffset);
+                                       }
                                }
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
                                /* if it was originally a RegTypeBase */
@@ -3326,6 +4126,16 @@ register.  Should this case include linux/ppc?
                                } else {
                                        ppc_mr (code, ppc_r11, ainfo->reg);
                                }
+
+                               if (cfg->tailcall_valuetype_addrs) {
+                                       MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
+
+                                       g_assert (ppc_is_imm16 (addr->inst_offset));
+                                       ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
+
+                                       tailcall_struct_index++;
+                               }
+
                                g_assert (ppc_is_imm16 (inst->inst_offset));
                                code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
                                /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
@@ -3403,7 +4213,6 @@ register.  Should this case include linux/ppc?
 void
 mono_arch_emit_epilog (MonoCompile *cfg)
 {
-       MonoJumpInfo *patch_info;
        MonoMethod *method = cfg->method;
        int pos, i;
        int max_epilog_size = 16 + 20*4;
@@ -3425,7 +4234,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        }
 
        /*
-        * Keep in sync with CEE_JMP
+        * Keep in sync with OP_JMP
         */
        code = cfg->native_code + cfg->code_len;
 
@@ -3527,12 +4336,10 @@ void
 mono_arch_emit_exceptions (MonoCompile *cfg)
 {
        MonoJumpInfo *patch_info;
-       int nthrows, i;
+       int i;
        guint8 *code;
        const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
        guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
-       guint32 code_size;
-       int exc_count = 0;
        int max_epilog_size = 50;
 
        /* count the number of exception infos */
@@ -3551,7 +4358,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
                        max_epilog_size += 12;
                else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
-                       MonoOvfJump *ovfj = patch_info->data.target;
+                       MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
                        i = exception_id_by_name (ovfj->data.exception);
                        if (!exc_throw_found [i]) {
                                max_epilog_size += 24;
@@ -3573,7 +4380,7 @@ 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_BB_OVF: {
-                       MonoOvfJump *ovfj = patch_info->data.target;
+                       MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
                        unsigned char *ip = patch_info->ip.i + cfg->native_code;
                        /* patch the initial jump */
                        ppc_patch (ip, code);
@@ -3587,7 +4394,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_EXC_OVF: {
-                       MonoOvfJump *ovfj = patch_info->data.target;
+                       MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
                        MonoJumpInfo *newji;
                        unsigned char *ip = patch_info->ip.i + cfg->native_code;
                        unsigned char *bcl = code;
@@ -3722,14 +4529,14 @@ setup_tls_access (void)
                                } else {
                                        ins = (guint32*) ((char*)ins + val);
                                }
-                               code = &val;
+                               code = (guint32*)&val;
                                ppc_li (code, ppc_r0, 0x7FF2);
                                if (ins [1] == val) {
                                        /* Darwin on G4, implement */
                                        tls_mode = TLS_MODE_FAILED;
                                        return;
                                } else {
-                                       code = &val;
+                                       code = (guint32*)&val;
                                        ppc_mfspr (code, ppc_r3, 104);
                                        if (ins [1] != val) {
                                                tls_mode = TLS_MODE_FAILED;
@@ -3802,7 +4609,7 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re
        /* add the this argument */
        if (this_reg != -1) {
                MonoInst *this;
-               MONO_INST_NEW (cfg, this, OP_SETREG);
+               MONO_INST_NEW (cfg, this, OP_MOVE);
                this->type = this_type;
                this->sreg1 = this_reg;
                this->dreg = mono_regstate_next_int (cfg->rs);
@@ -3812,7 +4619,7 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re
 
        if (vt_reg != -1) {
                MonoInst *vtarg;
-               MONO_INST_NEW (cfg, vtarg, OP_SETREG);
+               MONO_INST_NEW (cfg, vtarg, OP_MOVE);
                vtarg->type = STACK_MP;
                vtarg->sreg1 = vt_reg;
                vtarg->dreg = mono_regstate_next_int (cfg->rs);
@@ -3821,15 +4628,119 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re
        }
 }
 
+#ifdef MONO_ARCH_HAVE_IMT
+
+#define CMP_SIZE 12
+#define BR_SIZE 4
+#define JUMP_IMM_SIZE 12
+#define ENABLE_WRONG_METHOD_CHECK 0
+
+/*
+ * LOCKING: called with the domain lock held
+ */
+gpointer
+mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
+{
+       int i;
+       int size = 0;
+       guint8 *code, *start;
+
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+               if (item->is_equals) {
+                       if (item->check_target_idx) {
+                               if (!item->compare_done)
+                                       item->chunk_size += CMP_SIZE;
+                               item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
+                       } else {
+                               item->chunk_size += JUMP_IMM_SIZE;
+#if ENABLE_WRONG_METHOD_CHECK
+                               item->chunk_size += CMP_SIZE + BR_SIZE + 4;
+#endif
+                       }
+               } else {
+                       item->chunk_size += CMP_SIZE + BR_SIZE;
+                       imt_entries [item->check_target_idx]->compare_done = TRUE;
+               }
+               size += item->chunk_size;
+       }
+       /* the initial load of the vtable address */
+       size += 8;
+       code = mono_code_manager_reserve (domain->code_mp, size);
+       start = code;
+       ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+               item->code_target = code;
+               if (item->is_equals) {
+                       if (item->check_target_idx) {
+                               if (!item->compare_done) {
+                                       ppc_load (code, ppc_r0, (guint32)item->method);
+                                       ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
+                               }
+                               item->jmp_code = code;
+                               ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+                               ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
+                               ppc_mtctr (code, ppc_r0);
+                               ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+                       } else {
+                               /* enable the commented code to assert on wrong method */
+#if ENABLE_WRONG_METHOD_CHECK
+                               ppc_load (code, ppc_r0, (guint32)item->method);
+                               ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
+                               item->jmp_code = code;
+                               ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+#endif
+                               ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
+                               ppc_mtctr (code, ppc_r0);
+                               ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+#if ENABLE_WRONG_METHOD_CHECK
+                               ppc_patch (item->jmp_code, code);
+                               ppc_break (code);
+                               item->jmp_code = NULL;
+#endif
+                       }
+               } else {
+                       ppc_load (code, ppc_r0, (guint32)item->method);
+                       ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
+                       item->jmp_code = code;
+                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
+               }
+       }
+       /* patch the branches to get to the target items */
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+               if (item->jmp_code) {
+                       if (item->check_target_idx) {
+                               ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
+                       }
+               }
+       }
+               
+       mono_stats.imt_thunks_size += code - start;
+       g_assert (code - start <= size);
+       mono_arch_flush_icache (start, size);
+       return start;
+}
+
+MonoMethod*
+mono_arch_find_imt_method (gpointer *regs, guint8 *code)
+{
+       return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
+}
+
+MonoObject*
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
+{
+       return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
+}
+#endif
+
 MonoInst*
 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
        MonoInst *ins = NULL;
 
-       if (cmethod->klass == mono_defaults.thread_class &&
-                       strcmp (cmethod->name, "MemoryBarrier") == 0) {
-               MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
-       }
        /*if (cmethod->klass == mono_defaults.math_class) {
                if (strcmp (cmethod->name, "Sqrt") == 0) {
                        MONO_INST_NEW (cfg, ins, OP_SQRT);
@@ -3839,6 +4750,13 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethod
        return ins;
 }
 
+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)
 {
@@ -3872,3 +4790,9 @@ mono_arch_get_thread_intrinsic (MonoCompile* cfg)
        return ins;
 }
 
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+       /* FIXME: implement */
+       g_assert_not_reached ();
+}