Merge pull request #2822 from BrzVlad/feature-lshift-decomposition
[mono.git] / mono / mini / decompose.c
index 2dfff74b4fb6fbdf28dd94741eaef82865c8c795..9546009e724697247abc5e7e3e11ff1f67c8e685 100644 (file)
@@ -6,6 +6,7 @@
  *
  * (C) 2002 Ximian, Inc.
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "mini.h"
@@ -439,8 +440,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
        case OP_FCONV_TO_OVF_U8_UN:
        case OP_FCONV_TO_OVF_I_UN:
        case OP_FCONV_TO_OVF_U_UN:
-               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
-               cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
+               mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
                break;
 
        case OP_IDIV:
@@ -472,46 +472,67 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                }
                break;
 
-#if SIZEOF_REGISTER == 8
-       case OP_LREM_IMM:
-#endif
-       case OP_IREM_IMM: {
-               int power = mono_is_power_of_two (ins->inst_imm);
-               if (ins->inst_imm == 1) {
-                       ins->opcode = OP_ICONST;
-                       MONO_INST_NULLIFY_SREGS (ins);
-                       ins->inst_c0 = 0;
-#if __s390__
+#if SIZEOF_VOID_P == 8
+       case OP_LDIV:
+       case OP_LREM:
+       case OP_LDIV_UN:
+       case OP_LREM_UN:
+               if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
+                       emulate = TRUE;
+               if (!emulate) {
+                       if (cfg->backend->need_div_check) {
+                               int reg1 = alloc_ireg (cfg);
+                               int reg2 = alloc_ireg (cfg);
+                               int reg3 = alloc_ireg (cfg);
+                               /* b == 0 */
+                               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
+                               MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
+                               if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
+                                       /* b == -1 && a == 0x80000000 */
+                                       MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
+                                       MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
+                                       MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
+                                       MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
+                               }
+                       }
+                       MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
+                       NULLIFY_INS (ins);
                }
-#else
-               } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
-                       gboolean is_long = ins->opcode == OP_LREM_IMM;
-                       int compensator_reg = alloc_ireg (cfg);
-                       int intermediate_reg;
-
-                       /* Based on gcc code */
-
-                       /* Add compensation for negative numerators */
+               break;
+#endif
 
-                       if (power > 1) {
-                               intermediate_reg = compensator_reg;
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
-                       } else {
-                               intermediate_reg = ins->sreg1;
+       case OP_DIV_IMM:
+       case OP_REM_IMM:
+       case OP_IDIV_IMM:
+       case OP_IREM_IMM:
+       case OP_IDIV_UN_IMM:
+       case OP_IREM_UN_IMM:
+               if (cfg->backend->need_div_check) {
+                       int reg1 = alloc_ireg (cfg);
+                       /* b == 0 */
+                       if (ins->inst_imm == 0) {
+                               // FIXME: Optimize this
+                               MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
+                               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
+                               MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
                        }
-
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
-                       MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
-                       /* Compute remainder */
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
-                       /* Remove compensation */
-                       MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
-
+                       if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
+                               (ins->inst_imm == -1)) {
+                                       /* b == -1 && a == 0x80000000 */
+                                       MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
+                                       MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
+                       }
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
                        NULLIFY_INS (ins);
+               } else {
+                       emulate = TRUE;
                }
-#endif
                break;
-       }
 
        default:
                emulate = TRUE;
@@ -519,8 +540,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 +548,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 = (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];
-                               }
-                       }
-
-                       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 +608,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 +630,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 +662,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 +777,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,25 +914,27 @@ 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;
+#ifdef TARGET_POWERPC
+/* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
                        case OP_LSHR_UN_IMM:
                                if (tree->inst_c1 == 32) {
 
@@ -943,20 +943,12 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                         * later apply the speedup to the left shift as well
                                         * See BUG# 57957.
                                         */
-                                       /* 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);
-                               }
-                               break;
-
+#endif
                        case OP_LCOMPARE: {
                                MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
 
@@ -970,8 +962,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 +979,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 +993,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 +1012,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 +1035,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);
 
@@ -1243,7 +1235,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        break;
                                }
                                case OP_VZERO:
-                                       if (COMPILE_LLVM (cfg))
+                                       if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
                                                break;
 
                                        g_assert (ins->klass);
@@ -1321,9 +1313,6 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                case OP_OUTARG_VTRETADDR: {
                                        MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
 
-                                       if (COMPILE_LLVM (cfg))
-                                               break;
-
                                        src_var = get_vreg_to_inst (cfg, call->inst.dreg);
                                        if (!src_var)
                                                src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
@@ -1412,8 +1401,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
@@ -1547,7 +1536,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;
@@ -1647,19 +1636,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:
@@ -1884,4 +1873,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 */