[x86] Change the way exceptions are thrown from trampolines: instead of calling mono_...
[mono.git] / mono / mini / decompose.c
index d3fc7f2e92305f7f6cabeb442b61774466a2fe58..ea53056e69531214470fbd73a9eefad910f35dde 100644 (file)
@@ -519,8 +519,6 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
        }
 
        if (emulate) {
-               MonoJitICallInfo *info = NULL;
-
 #if SIZEOF_REGISTER == 8
                if (decompose_long_opcode (cfg, ins, &repl))
                        emulate = FALSE;
@@ -529,33 +527,8 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                        emulate = FALSE;
 #endif
 
-               if (emulate)
-                       info = mono_find_jit_opcode_emulation (ins->opcode);
-               if (info) {
-                       MonoInst **args;
-                       MonoInst *call;
-
-                       /* Create dummy MonoInst's for the arguments */
-                       g_assert (!info->sig->hasthis);
-                       g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
-
-                       args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
-                       if (info->sig->param_count > 0) {
-                               int sregs [MONO_MAX_SRC_REGS];
-                               int num_sregs, i;
-                               num_sregs = mono_inst_get_src_registers (ins, sregs);
-                               g_assert (num_sregs == info->sig->param_count);
-                               for (i = 0; i < num_sregs; ++i) {
-                                       MONO_INST_NEW (cfg, args [i], OP_ARG);
-                                       args [i]->dreg = sregs [i];
-                               }
-                       }
-
-                       call = mono_emit_jit_icall_by_info (cfg, info, args);
-                       call->dreg = ins->dreg;
-
-                       NULLIFY_INS (ins);
-               }
+               if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
+                       cfg->has_emulated_ops = TRUE;
        }
 
        if (ins->opcode == OP_NOP) {
@@ -614,8 +587,6 @@ mono_decompose_long_opts (MonoCompile *cfg)
         * needs to be able to handle long vregs.
         */
 
-       /* reg + 1 contains the ls word, reg + 2 contains the ms word */
-
        /**
         * Create a dummy bblock and emit code into it so we can use the normal 
         * code generation macros.
@@ -638,28 +609,28 @@ mono_decompose_long_opts (MonoCompile *cfg)
 
                        switch (tree->opcode) {
                        case OP_I8CONST:
-                               MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
+                               MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
                                break;
                        case OP_DUMMY_I8CONST:
-                               MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
-                               MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
+                               MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
+                               MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
                                break;
                        case OP_LMOVE:
                        case OP_LCONV_TO_U8:
                        case OP_LCONV_TO_I8:
                        case OP_LCONV_TO_OVF_U8_UN:
                        case OP_LCONV_TO_OVF_I8:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
                                break;
                        case OP_STOREI8_MEMBASE_REG:
-                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
-                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LOADI8_MEMBASE:
-                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
-                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
+                               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
                                break;
 
                        case OP_ICONV_TO_I8: {
@@ -670,108 +641,114 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                 * tmp = low > -1 ? 1: 0;
                                 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
                                 */
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
                                MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
                                break;
                        }
                        case OP_ICONV_TO_U8:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
-                               MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
+                               MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
                                break;
                        case OP_ICONV_TO_OVF_I8:
                                /* a signed 32 bit num always fits in a signed 64 bit one */
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
                                break;
                        case OP_ICONV_TO_OVF_U8:
                                MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
-                               MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
+                               MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
                                break;
                        case OP_ICONV_TO_OVF_I8_UN:
                        case OP_ICONV_TO_OVF_U8_UN:
                                /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
-                               MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
+                               MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
                                break;
                        case OP_LCONV_TO_I1:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_U1:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_I2:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_U2:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_I4:
                        case OP_LCONV_TO_U4:
                        case OP_LCONV_TO_I:
                        case OP_LCONV_TO_U:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
+#ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
                        case OP_LCONV_TO_R8:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
                                break;
+#endif
+#ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
                        case OP_LCONV_TO_R4:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
                                break;
+#endif
+#ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
                        case OP_LCONV_TO_R_UN:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
                                break;
+#endif
                        case OP_LCONV_TO_OVF_I1: {
                                MonoBasicBlock *is_negative, *end_label;
 
                                NEW_BBLOCK (cfg, is_negative);
                                NEW_BBLOCK (cfg, end_label);
 
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
 
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
 
                                /* Positive */
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
 
                                /* Negative */
                                MONO_START_BB (cfg, is_negative);
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
 
                                MONO_START_BB (cfg, end_label);
 
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        }
                        case OP_LCONV_TO_OVF_I1_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
 
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_U1:
                        case OP_LCONV_TO_OVF_U1_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
 
                                /* probe value to be within 0 to 255 */
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
                                break;
                        case OP_LCONV_TO_OVF_I2: {
                                MonoBasicBlock *is_negative, *end_label;
@@ -779,132 +756,132 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                NEW_BBLOCK (cfg, is_negative);
                                NEW_BBLOCK (cfg, end_label);
 
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
 
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
 
                                /* Positive */
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
 
                                /* Negative */
                                MONO_START_BB (cfg, is_negative);
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
                                MONO_START_BB (cfg, end_label);
 
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        }
                        case OP_LCONV_TO_OVF_I2_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
 
                                /* Probe value to be within -32768 and 32767 */
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
-                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_U2:
                        case OP_LCONV_TO_OVF_U2_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
 
                                /* Probe value to be within 0 and 65535 */
-                               MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
+                               MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
                                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
                                break;
                        case OP_LCONV_TO_OVF_I4:
                        case OP_LCONV_TO_OVF_I:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_U4:
                        case OP_LCONV_TO_OVF_U:
                        case OP_LCONV_TO_OVF_U4_UN:
                        case OP_LCONV_TO_OVF_U_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_I_UN:
                        case OP_LCONV_TO_OVF_I4_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_U8:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
 
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
                                break;
                        case OP_LCONV_TO_OVF_I8_UN:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
                                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
 
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
                                break;
 
                        case OP_LADD:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                break;
                        case OP_LSUB:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                break;
 
                        case OP_LADD_OVF:
                                /* ADC sets the condition code */
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
                                break;
                        case OP_LADD_OVF_UN:
                                /* ADC sets the condition code */
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                                break;
                        case OP_LSUB_OVF:
                                /* SBB sets the condition code */
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
                                break;
                        case OP_LSUB_OVF_UN:
                                /* SBB sets the condition code */
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                                break;
                        case OP_LAND:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                break;
                        case OP_LOR:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                break;
                        case OP_LXOR:
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
-                               MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                break;
                        case OP_LNOT:
-                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
+                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
                                break;
                        case OP_LNEG:
                                /* Handled in mono_arch_decompose_long_opts () */
@@ -916,24 +893,24 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                break;
 
                        case OP_LADD_IMM:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
                        case OP_LSUB_IMM:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
                        case OP_LAND_IMM:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
                        case OP_LOR_IMM:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
                        case OP_LXOR_IMM:
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
                        case OP_LSHR_UN_IMM:
                                if (tree->inst_c1 == 32) {
@@ -945,15 +922,15 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                         */
                                        /* FIXME: Move this to the strength reduction pass */
                                        /* just move the upper half to the lower and zero the high word */
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
-                                       MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
+                                       MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
                                }
                                break;
                        case OP_LSHL_IMM:
                                if (tree->inst_c1 == 32) {
                                        /* just move the lower half to the upper and zero the lower word */
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
-                                       MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
+                                       MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
                                }
                                break;
 
@@ -970,8 +947,8 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                        /* Branchless version based on gcc code */
                                        d1 = alloc_ireg (cfg);
                                        d2 = alloc_ireg (cfg);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
                                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
                                        MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
@@ -987,11 +964,11 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                case OP_LBLE_UN:
                                case OP_LBLT_UN:
                                        /* Convert into three comparisons + branches */
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
                                        NULLIFY_INS (next);
                                        break;
@@ -1001,8 +978,8 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                        /* Branchless version based on gcc code */
                                        d1 = alloc_ireg (cfg);
                                        d2 = alloc_ireg (cfg);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
 
                                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
@@ -1020,11 +997,11 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                        NEW_BBLOCK (cfg, set_to_1);
 
                                        MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
-                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
                                        MONO_START_BB (cfg, set_to_1);
                                        MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
@@ -1043,8 +1020,8 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
                                guint32 low_imm = tree->inst_ls_word;
                                guint32 high_imm = tree->inst_ms_word;
-                               int low_reg = tree->sreg1 + 1;
-                               int high_reg = tree->sreg1 + 2;
+                               int low_reg = MONO_LVREG_LS (tree->sreg1);
+                               int high_reg = MONO_LVREG_MS (tree->sreg1);
 
                                g_assert (next);
 
@@ -1197,9 +1174,11 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
         * Create a dummy bblock and emit code into it so we can use the normal 
         * code generation macros.
         */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+       cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
        first_bb = cfg->cbb;
 
+       /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
+
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                MonoInst *ins;
                MonoInst *prev = NULL;
@@ -1218,11 +1197,12 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                        for (ins = bb->code; ins; ins = ins->next) {
                                switch (ins->opcode) {
                                case OP_VMOVE: {
+                                       g_assert (ins->klass);
+                                       if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
+                                               break;
                                        src_var = get_vreg_to_inst (cfg, ins->sreg1);
                                        dest_var = get_vreg_to_inst (cfg, ins->dreg);
 
-                                       g_assert (ins->klass);
-
                                        if (!src_var)
                                                src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
 
@@ -1240,6 +1220,9 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        break;
                                }
                                case OP_VZERO:
+                                       if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
+                                               break;
+
                                        g_assert (ins->klass);
 
                                        EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
@@ -1258,6 +1241,9 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        }
                                        break;
                                case OP_DUMMY_VZERO:
+                                       if (COMPILE_LLVM (cfg))
+                                               break;
+
                                        NULLIFY_INS (ins);
                                        break;
                                case OP_STOREV_MEMBASE: {
@@ -1277,6 +1263,8 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                }
                                case OP_LOADV_MEMBASE: {
                                        g_assert (ins->klass);
+                                       if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
+                                               break;
 
                                        dest_var = get_vreg_to_inst (cfg, ins->dreg);
                                        // FIXME-VT:
@@ -1291,6 +1279,9 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        break;
                                }
                                case OP_OUTARG_VT: {
+                                       if (COMPILE_LLVM (cfg))
+                                               break;
+
                                        g_assert (ins->klass);
 
                                        src_var = get_vreg_to_inst (cfg, ins->sreg1);
@@ -1322,6 +1313,9 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        MonoCallInst *call = (MonoCallInst*)ins;
                                        int size;
 
+                                       if (COMPILE_LLVM (cfg))
+                                               break;
+
                                        if (call->vret_in_reg) {
                                                MonoCallInst *call2;
 
@@ -1392,8 +1386,8 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                                                break;
                                                        }
                                                        call2->inst.dreg = alloc_lreg (cfg);
-                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
-                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
 #else
                                                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
 #endif
@@ -1442,71 +1436,6 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
        }
 }
 
-void
-mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb, *first_bb;
-
-       /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
-
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-       first_bb = cfg->cbb;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MonoInst *prev = NULL;
-               MonoInst *src_var, *src, *dest;
-               gboolean restart;
-               int dreg;
-
-               if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
-
-               cfg->cbb->code = cfg->cbb->last_ins = NULL;
-               restart = TRUE;
-
-               while (restart) {
-                       restart = FALSE;
-
-                       for (ins = bb->code; ins; ins = ins->next) {
-                               switch (ins->opcode) {
-                               case OP_STOREV_MEMBASE: {
-                                       src_var = get_vreg_to_inst (cfg, ins->sreg1);
-
-                                       if (!src_var) {
-                                               g_assert (ins->klass);
-                                               src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
-                                       }
-
-                                       EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
-
-                                       dreg = alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
-                                       mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
-                                       break;
-                               }
-                               default:
-                                       break;
-                               }
-
-                               g_assert (cfg->cbb == first_bb);
-
-                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
-                                       /* Replace the original instruction with the new code sequence */
-
-                                       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-                                       first_bb->code = first_bb->last_ins = NULL;
-                                       first_bb->in_count = first_bb->out_count = 0;
-                                       cfg->cbb = first_bb;
-                               }
-                               else
-                                       prev = ins;
-                       }
-               }
-
-               if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
-       }
-}
-
 inline static MonoInst *
 mono_get_domainvar (MonoCompile *cfg)
 {
@@ -1534,7 +1463,7 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
         * Create a dummy bblock and emit code into it so we can use the normal 
         * code generation macros.
         */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+       cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
        first_bb = cfg->cbb;
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -1592,7 +1521,7 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                                                if (managed_alloc)
                                                        dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                                                else
-                                                       dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
+                                                       dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
                                                dest->dreg = ins->dreg;
                                        }
                                        break;
@@ -1692,19 +1621,19 @@ mono_decompose_soft_float (MonoCompile *cfg)
                                        break;
                                case OP_FGETLOW32:
                                        ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 1;
+                                       ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
                                        break;
                                case OP_FGETHIGH32:
                                        ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 2;
+                                       ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
                                        break;
                                case OP_SETFRET: {
                                        int reg = ins->sreg1;
 
                                        ins->opcode = OP_SETLRET;
                                        ins->dreg = -1;
-                                       ins->sreg1 = reg + 1;
-                                       ins->sreg2 = reg + 2;
+                                       ins->sreg1 = MONO_LVREG_LS (reg);
+                                       ins->sreg2 = MONO_LVREG_MS (reg);
                                        break;
                                }
                                case OP_LOADR8_MEMBASE:
@@ -1929,4 +1858,89 @@ mono_decompose_soft_float (MonoCompile *cfg)
 
 #endif
 
+void
+mono_local_emulate_ops (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+       gboolean inlined_wrapper = FALSE;
+
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               MonoInst *ins;
+
+               MONO_BB_FOR_EACH_INS (bb, ins) {
+                       int op_noimm = mono_op_imm_to_op (ins->opcode);
+                       MonoJitICallInfo *info;
+
+                       /*
+                        * Emulation can't handle _IMM ops. If this is an imm opcode we need
+                        * to check whether its non-imm counterpart is emulated and, if so,
+                        * decompose it back to its non-imm counterpart.
+                        */
+                       if (op_noimm != -1)
+                               info = mono_find_jit_opcode_emulation (op_noimm);
+                       else
+                               info = mono_find_jit_opcode_emulation (ins->opcode);
+
+                       if (info) {
+                               MonoInst **args;
+                               MonoInst *call;
+                               MonoBasicBlock *first_bb;
+
+                               /* Create dummy MonoInst's for the arguments */
+                               g_assert (!info->sig->hasthis);
+                               g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
+
+                               if (op_noimm != -1)
+                                       mono_decompose_op_imm (cfg, bb, ins);
+
+                               args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
+                               if (info->sig->param_count > 0) {
+                                       int sregs [MONO_MAX_SRC_REGS];
+                                       int num_sregs, i;
+                                       num_sregs = mono_inst_get_src_registers (ins, sregs);
+                                       g_assert (num_sregs == info->sig->param_count);
+                                       for (i = 0; i < num_sregs; ++i) {
+                                               MONO_INST_NEW (cfg, args [i], OP_ARG);
+                                               args [i]->dreg = sregs [i];
+                                       }
+                               }
+
+                               /* We emit the call on a separate dummy basic block */
+                               cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+                               first_bb = cfg->cbb;
+
+                               call = mono_emit_jit_icall_by_info (cfg, info, args);
+                               call->dreg = ins->dreg;
+
+                               /* Replace ins with the emitted code and do the necessary bb linking */
+                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
+                                       MonoInst *saved_prev = ins->prev;
+
+                                       mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
+                                       first_bb->code = first_bb->last_ins = NULL;
+                                       first_bb->in_count = first_bb->out_count = 0;
+                                       cfg->cbb = first_bb;
+
+                                       /* ins is hanging, continue scanning the emitted code */
+                                       ins = saved_prev;
+                               } else {
+                                       g_error ("Failed to emit emulation code");
+                               }
+                               inlined_wrapper = TRUE;
+                       }
+               }
+       }
+
+       /*
+        * Avoid rerunning these passes by emitting directly the exception checkpoint
+        * at IR level, instead of inlining the icall wrapper. FIXME
+        */
+       if (inlined_wrapper) {
+               if (!COMPILE_LLVM (cfg))
+                       mono_decompose_long_opts (cfg);
+               if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
+                       mono_local_cprop (cfg);
+       }
+}
+
 #endif /* DISABLE_JIT */