* Zoltan Varga (vargaz@gmail.com)
*
* (C) 2002 Ximian, Inc.
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
#include "mini.h"
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:
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;
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;
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);
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);
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;
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;
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);
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);
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
/*
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) {
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);
}
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;
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);
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 */
/* 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);