Merge pull request #601 from knocte/sock_improvements
[mono.git] / mono / mini / decompose.c
index 59c2b2983d0206732acd91d65546595a637a26ca..b86678d4e2305694c31a6a5706e162f09f10af0e 100644 (file)
@@ -5,6 +5,7 @@
  *   Zoltan Varga (vargaz@gmail.com)
  *
  * (C) 2002 Ximian, Inc.
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  */
 
 #include "mini.h"
@@ -20,152 +21,17 @@ MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMetho
 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
 
-/*
- * mono_decompose_opcode:
- *
- *   Decompose complex opcodes into ones closer to opcodes supported by
- * the given architecture.
- * Returns a MonoInst which represents the result of the decomposition, and can
- * be pushed on the IL stack. This is needed because the original instruction is
- * nullified.
- */
-MonoInst*
-mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
+/* Decompose complex long opcodes on 64 bit machines or when using LLVM */
+static gboolean
+decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
 {
        MonoInst *repl = NULL;
-       int type = ins->type;
-       int dreg = ins->dreg;
-
-       /* FIXME: Instead of = NOP, don't emit the original ins at all */
 
-#ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
-       mono_arch_decompose_opts (cfg, ins);
-#endif
+       *repl_ins = NULL;
 
-       /*
-        * The code below assumes that we are called immediately after emitting 
-        * ins. This means we can emit code using the normal code generation
-        * macros.
-        */
        switch (ins->opcode) {
-       /* this doesn't make sense on ppc and other architectures */
-#if !defined(MONO_ARCH_NO_IOV_CHECK)
-       case OP_IADD_OVF:
-               if (COMPILE_LLVM (cfg))
-                       break;
-               ins->opcode = OP_IADDCC;
-               MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
-               break;
-       case OP_IADD_OVF_UN:
-               if (COMPILE_LLVM (cfg))
-                       break;
-               ins->opcode = OP_IADDCC;
-               MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
-               break;
-       case OP_ISUB_OVF:
-               if (COMPILE_LLVM (cfg))
-                       break;
-               ins->opcode = OP_ISUBCC;
-               MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
-               break;
-       case OP_ISUB_OVF_UN:
-               if (COMPILE_LLVM (cfg))
-                       break;
-               ins->opcode = OP_ISUBCC;
-               MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
-               break;
-#endif
-       case OP_ICONV_TO_OVF_I1:
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
-               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
-               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_I1_UN:
-               /* probe values between 0 to 127 */
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
-               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_U1:
-       case OP_ICONV_TO_OVF_U1_UN:
-               /* probe value to be within 0 to 255 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_I2:
-               /* Probe value to be within -32768 and 32767 */
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
-               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
-               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_I2_UN:
-               /* Convert uint value into short, value within 0 and 32767 */
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
-               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_U2:
-       case OP_ICONV_TO_OVF_U2_UN:
-               /* Probe value to be within 0 and 65535 */
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
-               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_OVF_U4:
-       case OP_ICONV_TO_OVF_I4_UN:
-#if SIZEOF_REGISTER == 4
-       case OP_ICONV_TO_OVF_U:
-       case OP_ICONV_TO_OVF_I_UN:
-#endif
-               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
-               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
-               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
-               NULLIFY_INS (ins);
-               break;
-       case OP_ICONV_TO_I4:
-       case OP_ICONV_TO_U4:
-       case OP_ICONV_TO_OVF_I4:
-#if SIZEOF_REGISTER == 4
-       case OP_ICONV_TO_OVF_I:
-       case OP_ICONV_TO_OVF_U_UN:
-#endif
-               ins->opcode = OP_MOVE;
-               break;
-       case OP_ICONV_TO_I:
-#if SIZEOF_REGISTER == 8
-               ins->opcode = OP_SEXT_I4;
-#else
-               ins->opcode = OP_MOVE;
-#endif
-               break;
-       case OP_ICONV_TO_U:
-#if SIZEOF_REGISTER == 8
-               ins->opcode = OP_ZEXT_I4;
-#else
-               ins->opcode = OP_MOVE;
-#endif
-               break;
-
-       case OP_FCONV_TO_R8:
-               ins->opcode = OP_FMOVE;
-               break;
-
-               /* Long opcodes on 64 bit machines */
-#if SIZEOF_REGISTER == 8
        case OP_LCONV_TO_I4:
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
-               NULLIFY_INS (ins);
+               ins->opcode = OP_SEXT_I4;
                break;
        case OP_LCONV_TO_I8:
        case OP_LCONV_TO_I:
@@ -187,14 +53,30 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
        case OP_LADD_OVF:
                if (COMPILE_LLVM (cfg))
                        break;
-               EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
+               {
+                       int opcode;
+#if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
+                       opcode = OP_LADDCC;
+#else
+                       opcode = OP_ADDCC;
+#endif
+                       EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
+               }
                MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
                NULLIFY_INS (ins);
                break;
        case OP_LADD_OVF_UN:
                if (COMPILE_LLVM (cfg))
                        break;
-               EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
+               {
+                       int opcode;
+#if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
+                       opcode = OP_LADDCC;
+#else
+                       opcode = OP_ADDCC;
+#endif
+                       EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
+               }
                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                NULLIFY_INS (ins);
                break;
@@ -202,14 +84,30 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
        case OP_LSUB_OVF:
                if (COMPILE_LLVM (cfg))
                        break;
-               EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
+               {
+                       int opcode;
+#if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
+                       opcode = OP_LSUBCC;
+#else
+                       opcode = OP_SUBCC;
+#endif
+                       EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
+               }
                MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
                NULLIFY_INS (ins);
                break;
        case OP_LSUB_OVF_UN:
                if (COMPILE_LLVM (cfg))
                        break;
-               EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
+               {
+                       int opcode;
+#if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
+                       opcode = OP_LSUBCC;
+#else
+                       opcode = OP_SUBCC;
+#endif
+                       EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
+               }
                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                NULLIFY_INS (ins);
                break;
@@ -221,7 +119,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                break;
        case OP_ICONV_TO_OVF_U8:
        case OP_ICONV_TO_OVF_U:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
@@ -236,88 +134,93 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I1:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I1_UN:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U1:
                /* probe value to be within 0 to 255 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U1_UN:
                /* probe value to be within 0 to 255 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I2:
                /* Probe value to be within -32768 and 32767 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I2_UN:
                /* Probe value to be within 0 and 32767 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U2:
                /* Probe value to be within 0 and 65535 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U2_UN:
                /* Probe value to be within 0 and 65535 */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I4:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
                /* The int cast is needed for the VS compiler.  See Compiler Warning (level 2) C4146. */
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
+#if SIZEOF_REGISTER == 8
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
+#else
+               g_assert (COMPILE_LLVM (cfg));
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
+#endif
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_I4_UN:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U4:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
                MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U4_UN:
-               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
                MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
@@ -330,23 +233,194 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                break;
        case OP_LCONV_TO_OVF_I_UN:
        case OP_LCONV_TO_OVF_I8_UN:
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
        case OP_LCONV_TO_OVF_U8:
        case OP_LCONV_TO_OVF_U:
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
+               MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
                MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
                NULLIFY_INS (ins);
                break;
+       default:
+               return FALSE;
+       }
+
+       *repl_ins = repl;
+       return TRUE;
+}
+
+/*
+ * mono_decompose_opcode:
+ *
+ *   Decompose complex opcodes into ones closer to opcodes supported by
+ * the given architecture.
+ * Returns a MonoInst which represents the result of the decomposition, and can
+ * be pushed on the IL stack. This is needed because the original instruction is
+ * nullified.
+ * Sets the cfg exception if an opcode is not supported.
+ */
+MonoInst*
+mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
+{
+       MonoInst *repl = NULL;
+       int type = ins->type;
+       int dreg = ins->dreg;
+
+       /* FIXME: Instead of = NOP, don't emit the original ins at all */
+
+#ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
+       mono_arch_decompose_opts (cfg, ins);
 #endif
 
+       /*
+        * The code below assumes that we are called immediately after emitting 
+        * ins. This means we can emit code using the normal code generation
+        * macros.
+        */
+       switch (ins->opcode) {
+       /* this doesn't make sense on ppc and other architectures */
+#if !defined(MONO_ARCH_NO_IOV_CHECK)
+       case OP_IADD_OVF:
+               if (COMPILE_LLVM (cfg))
+                       break;
+               ins->opcode = OP_IADDCC;
+               MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
+               break;
+       case OP_IADD_OVF_UN:
+               if (COMPILE_LLVM (cfg))
+                       break;
+               ins->opcode = OP_IADDCC;
+               MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
+               break;
+       case OP_ISUB_OVF:
+               if (COMPILE_LLVM (cfg))
+                       break;
+               ins->opcode = OP_ISUBCC;
+               MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
+               break;
+       case OP_ISUB_OVF_UN:
+               if (COMPILE_LLVM (cfg))
+                       break;
+               ins->opcode = OP_ISUBCC;
+               MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
+               break;
+#endif
+       case OP_ICONV_TO_OVF_I1:
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
+               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_I1_UN:
+               /* probe values between 0 to 127 */
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_U1:
+       case OP_ICONV_TO_OVF_U1_UN:
+               /* probe value to be within 0 to 255 */
+               MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_I2:
+               /* Probe value to be within -32768 and 32767 */
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
+               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_I2_UN:
+               /* Convert uint value into short, value within 0 and 32767 */
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_U2:
+       case OP_ICONV_TO_OVF_U2_UN:
+               /* Probe value to be within 0 and 65535 */
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
+               MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_OVF_U4:
+       case OP_ICONV_TO_OVF_I4_UN:
+#if SIZEOF_VOID_P == 4
+       case OP_ICONV_TO_OVF_U:
+       case OP_ICONV_TO_OVF_I_UN:
+#endif
+               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
+               MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
+               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
+               NULLIFY_INS (ins);
+               break;
+       case OP_ICONV_TO_I4:
+       case OP_ICONV_TO_U4:
+       case OP_ICONV_TO_OVF_I4:
+       case OP_ICONV_TO_OVF_U4_UN:
+#if SIZEOF_VOID_P == 4
+       case OP_ICONV_TO_OVF_I:
+       case OP_ICONV_TO_OVF_U_UN:
+#endif
+               ins->opcode = OP_MOVE;
+               break;
+       case OP_ICONV_TO_I:
+#if SIZEOF_VOID_P == 8
+               ins->opcode = OP_SEXT_I4;
+#else
+               ins->opcode = OP_MOVE;
+#endif
+               break;
+       case OP_ICONV_TO_U:
+#if SIZEOF_VOID_P == 8
+               ins->opcode = OP_ZEXT_I4;
+#else
+               ins->opcode = OP_MOVE;
+#endif
+               break;
+
+       case OP_FCONV_TO_R8:
+               ins->opcode = OP_FMOVE;
+               break;
+
+       case OP_FCONV_TO_OVF_I1_UN:
+       case OP_FCONV_TO_OVF_I2_UN:
+       case OP_FCONV_TO_OVF_I4_UN:
+       case OP_FCONV_TO_OVF_I8_UN:
+       case OP_FCONV_TO_OVF_U1_UN:
+       case OP_FCONV_TO_OVF_U2_UN:
+       case OP_FCONV_TO_OVF_U4_UN:
+       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.");
+               break;
+
        default: {
                MonoJitICallInfo *info;
 
+#if SIZEOF_REGISTER == 8
+               if (decompose_long_opcode (cfg, ins, &repl))
+                       break;
+#else
+               if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
+                       break;
+#endif
+
                info = mono_find_jit_opcode_emulation (ins->opcode);
                if (info) {
                        MonoInst **args;
@@ -468,6 +542,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
                        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);
                                break;
@@ -1062,6 +1137,18 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
 
                                        EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
                                        mini_emit_initobj (cfg, dest, NULL, ins->klass);
+                                       
+                                       if (cfg->compute_gc_maps) {
+                                               MonoInst *tmp;
+
+                                               /* 
+                                                * Tell the GC map code that the vtype is considered live after
+                                                * the initialization.
+                                                */
+                                               MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
+                                               tmp->inst_c1 = ins->dreg;
+                                               MONO_ADD_INS (cfg->cbb, tmp);
+                                       }
                                        break;
                                case OP_STOREV_MEMBASE: {
                                        src_var = get_vreg_to_inst (cfg, ins->sreg1);
@@ -1082,6 +1169,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                        g_assert (ins->klass);
 
                                        dest_var = get_vreg_to_inst (cfg, ins->dreg);
+                                       // FIXME-VT:
                                        // FIXME:
                                        if (!dest_var)
                                                dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
@@ -1162,9 +1250,13 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                                case 2:
                                                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
                                                        break;
+                                               case 3:
                                                case 4:
                                                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
                                                        break;
+                                               case 5:
+                                               case 6:
+                                               case 7:
                                                case 8:
 #if SIZEOF_REGISTER == 4
                                                        /*
@@ -1284,13 +1376,16 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                        for (ins = bb->code; ins; ins = ins->next) {
                                switch (ins->opcode) {
                                case OP_LDLEN:
-                                       NEW_LOAD_MEMBASE_FAULT (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
-                                                                                       G_STRUCT_OFFSET (MonoArray, max_length));
+                                       NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
+                                                                                       G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
                                        MONO_ADD_INS (cfg->cbb, dest);
                                        break;
                                case OP_BOUNDS_CHECK:
                                        MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
-                                       MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
+                                       if (COMPILE_LLVM (cfg))
+                                               MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
+                                       else
+                                               MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
                                        break;
                                case OP_NEWARR:
                                        if (cfg->opt & MONO_OPT_SHARED) {
@@ -1302,8 +1397,9 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                                                dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
                                                dest->dreg = ins->dreg;
                                        } else {
-                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
-                                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
+                                               MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
+                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
+                                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
 
                                                g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
                                                NEW_VTABLECONST (cfg, iargs [0], vtable);
@@ -1319,8 +1415,8 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                                        }
                                        break;
                                case OP_STRLEN:
-                                       MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOADI4_MEMBASE, ins->dreg,
-                                                                                                                ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
+                                       MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
+                                                                                                                ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
                                        break;
                                default:
                                        break;
@@ -1469,6 +1565,7 @@ mono_decompose_soft_float (MonoCompile *cfg)
                                                MonoCallInst *call2;
                                                MonoInst *iargs [1];
                                                MonoInst *conv;
+                                               GSList *l;
 
                                                /* Convert the call into a call returning an int */
                                                MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
@@ -1489,6 +1586,10 @@ mono_decompose_soft_float (MonoCompile *cfg)
                                                call2->inst.dreg = mono_alloc_ireg (cfg);
                                                MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
 
+                                               /* Remap OUTARG_VT instructions referencing this call */
+                                               for (l = call->outarg_vts; l; l = l->next)
+                                                       ((MonoInst*)(l->data))->inst_p0 = call2;
+
                                                /* FIXME: Optimize this */
 
                                                /* Emit an r4->r8 conversion */
@@ -1522,8 +1623,18 @@ mono_decompose_soft_float (MonoCompile *cfg)
 
                                        /* Convert fcompare+fbcc to icall+icompare+beq */
 
+                                       if (!ins->next) {
+                                               /* The branch might be optimized away */
+                                               NULLIFY_INS (ins);
+                                               break;
+                                       }
+
                                        info = mono_find_jit_opcode_emulation (ins->next->opcode);
-                                       g_assert (info);
+                                       if (!info) {
+                                               /* The branch might be optimized away */
+                                               NULLIFY_INS (ins);
+                                               break;
+                                       }
 
                                        /* Create dummy MonoInst's for the arguments */
                                        MONO_INST_NEW (cfg, iargs [0], OP_ARG);