#include "mini.h"
#include "ir-emit.h"
+#ifndef DISABLE_JIT
+
/* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
*
* 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.
*/
-void
+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
/* 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;
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);
- ins->opcode = OP_NOP;
+ 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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_ICONV_TO_OVF_U1:
case OP_ICONV_TO_OVF_U1_UN:
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);
- ins->opcode = OP_NOP;
+ 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, -32768);
MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ 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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_ICONV_TO_OVF_U2:
case OP_ICONV_TO_OVF_U2_UN:
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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_ICONV_TO_OVF_U4:
case OP_ICONV_TO_OVF_I4_UN:
-#if SIZEOF_VOID_P == 4
+#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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_ICONV_TO_I4:
case OP_ICONV_TO_U4:
case OP_ICONV_TO_OVF_I4:
-#if SIZEOF_VOID_P == 4
+#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_VOID_P == 8
+#if SIZEOF_REGISTER == 8
ins->opcode = OP_SEXT_I4;
#else
ins->opcode = OP_MOVE;
#endif
break;
case OP_ICONV_TO_U:
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
ins->opcode = OP_ZEXT_I4;
#else
ins->opcode = OP_MOVE;
break;
/* Long opcodes on 64 bit machines */
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
case OP_LCONV_TO_I4:
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_I8:
case OP_LCONV_TO_I:
case OP_LCONV_TO_U4:
/* Clean out the upper word */
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LADD_OVF:
- MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
+ if (COMPILE_LLVM (cfg))
+ break;
+ EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LADD_OVF_UN:
- MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
+ if (COMPILE_LLVM (cfg))
+ break;
+ EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
+#ifndef __mono_ppc64__
case OP_LSUB_OVF:
- MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
+ if (COMPILE_LLVM (cfg))
+ break;
+ EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LSUB_OVF_UN:
- MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
+ if (COMPILE_LLVM (cfg))
+ break;
+ EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
+#endif
case OP_ICONV_TO_OVF_I8:
case OP_ICONV_TO_OVF_I:
MONO_EMIT_NEW_COMPARE_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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
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 */
/* Clean out the upper word */
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_I1:
MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
MONO_EMIT_NEW_COMPARE_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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_I1_UN:
MONO_EMIT_NEW_COMPARE_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);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, GT_UN, "OverflowException");
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, GT_UN, "OverflowException");
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
- ins->opcode = OP_NOP;
+ 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, -32768);
MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, GT_UN, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, GT_UN, "OverflowException");
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, GT_UN, "OverflowException");
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_I4:
MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_I4_UN:
MONO_EMIT_NEW_COMPARE_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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_U4:
MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_U4_UN:
MONO_EMIT_NEW_COMPARE_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);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
case OP_LCONV_TO_OVF_I:
case OP_LCONV_TO_OVF_U_UN:
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ 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_COND_EXC (cfg, LT, "OverflowException");
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
break;
#endif
/* Create dummy MonoInst's for the arguments */
g_assert (!info->sig->hasthis);
- g_assert (info->sig->param_count <= 2);
+ g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
if (info->sig->param_count > 0) {
- MONO_INST_NEW (cfg, args [0], OP_ARG);
- args [0]->dreg = ins->sreg1;
- }
- if (info->sig->param_count > 1) {
- MONO_INST_NEW (cfg, args [1], OP_ARG);
- args [1]->dreg = ins->sreg2;
+ 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_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
call->dreg = ins->dreg;
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
}
break;
}
}
+
+ if (ins->opcode == OP_NOP) {
+ if (repl) {
+ repl->type = type;
+ return repl;
+ } else {
+ /* Use the last emitted instruction */
+ ins = cfg->cbb->last_ins;
+ g_assert (ins);
+ ins->type = type;
+ g_assert (ins->dreg == dreg);
+ return ins;
+ }
+ } else {
+ return ins;
+ }
}
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
static int lbr_decomp [][2] = {
{0, 0}, /* BEQ */
{OP_IBGT, OP_IBGE_UN}, /* BGE */
void
mono_decompose_long_opts (MonoCompile *cfg)
{
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
MonoBasicBlock *bb, *first_bb;
/*
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);
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_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
break;
case OP_LNEG:
- /*
- * FIXME: The original version in inssel-long32.brg does not work
- * on x86, and the x86 version might not work on other archs ?
- */
- /* FIXME: Move these to mono_arch_decompose_long_opts () */
-#if defined(__i386__)
- MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
- MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
-#elif defined(__sparc__)
- MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
- MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
-#elif defined(__arm__)
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
-#else
- NOT_IMPLEMENTED;
-#endif
+ /* Handled in mono_arch_decompose_long_opts () */
+ g_assert_not_reached ();
break;
case OP_LMUL:
/* Emulated */
gboolean restart;
int dreg;
- if (cfg->verbose_level > 1) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
+ if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
cfg->cbb->code = cfg->cbb->last_ins = NULL;
restart = TRUE;
/* Save the result */
if (dest_var->backend.is_pinvoke)
- size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
+ size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
else
size = mono_type_size (dest_var->inst_vtype, NULL);
switch (size) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
break;
case 8:
+#if SIZEOF_REGISTER == 4
+ /*
+ FIXME Other ABIs might return in different regs than the ones used for LCALL.
+ FIXME It would be even nicer to be able to leverage the long decompose stuff.
+ */
+ switch (call2->inst.opcode) {
+ case OP_CALL:
+ call2->inst.opcode = OP_LCALL;
+ break;
+ case OP_CALL_REG:
+ call2->inst.opcode = OP_LCALL_REG;
+ break;
+ case OP_CALL_MEMBASE:
+ call2->inst.opcode = OP_LCALL_MEMBASE;
+ 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);
+#else
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+#endif
break;
default:
/* This assumes the vtype is sizeof (gpointer) long */
}
}
- if (cfg->verbose_level > 1) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
+ if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
}
}
+
+#endif /* DISABLE_JIT */