* Zoltan Varga (vargaz@gmail.com)
*
* (C) 2002 Ximian, Inc.
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
#include "mini.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);
+MONO_API 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);
void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
switch (ins->opcode) {
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;
MonoInst *repl = NULL;
int type = ins->type;
int dreg = ins->dreg;
+ gboolean emulate = FALSE;
/* FIXME: Instead of = NOP, don't emit the original ins at all */
break;
case OP_ICONV_TO_OVF_U4:
case OP_ICONV_TO_OVF_I4_UN:
-#if SIZEOF_REGISTER == 4
+#if SIZEOF_VOID_P == 4
case OP_ICONV_TO_OVF_U:
case OP_ICONV_TO_OVF_I_UN:
#endif
case OP_ICONV_TO_U4:
case OP_ICONV_TO_OVF_I4:
case OP_ICONV_TO_OVF_U4_UN:
-#if SIZEOF_REGISTER == 4
+#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_REGISTER == 8
+#if SIZEOF_VOID_P == 8
ins->opcode = OP_SEXT_I4;
#else
ins->opcode = OP_MOVE;
#endif
break;
case OP_ICONV_TO_U:
-#if SIZEOF_REGISTER == 8
+#if SIZEOF_VOID_P == 8
ins->opcode = OP_ZEXT_I4;
#else
ins->opcode = OP_MOVE;
cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
break;
- default: {
- MonoJitICallInfo *info;
+#if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
+ case OP_IDIV:
+ case OP_IREM:
+ case OP_IDIV_UN:
+ case OP_IREM_UN:
+ if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
+#ifdef MONO_ARCH_NEED_DIV_CHECK
+ int reg1 = alloc_ireg (cfg);
+ int reg2 = alloc_ireg (cfg);
+ /* b == 0 */
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
+ MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
+ if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
+ /* b == -1 && a == 0x80000000 */
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
+ MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
+ MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, 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, "DivideByZeroException");
+ }
+#endif
+ MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
+ ins->opcode = OP_NOP;
+ } else {
+ emulate = TRUE;
+ }
+ break;
+#endif
+
+ default:
+ emulate = TRUE;
+ break;
+ }
+
+ if (emulate) {
+ MonoJitICallInfo *info = NULL;
#if SIZEOF_REGISTER == 8
if (decompose_long_opcode (cfg, ins, &repl))
- break;
+ emulate = FALSE;
#else
if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
- break;
+ emulate = FALSE;
#endif
- info = mono_find_jit_opcode_emulation (ins->opcode);
+ if (emulate)
+ info = mono_find_jit_opcode_emulation (ins->opcode);
if (info) {
MonoInst **args;
MonoInst *call;
NULLIFY_INS (ins);
}
- break;
- }
}
if (ins->opcode == OP_NOP) {
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
/*
}
}
+void
+mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
+{
+ MonoBasicBlock *bb, *first_bb;
+
+ /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
+
+ cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+ first_bb = cfg->cbb;
+
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ MonoInst *ins;
+ MonoInst *prev = NULL;
+ MonoInst *src_var, *src, *dest;
+ gboolean restart;
+ int dreg;
+
+ if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
+
+ cfg->cbb->code = cfg->cbb->last_ins = NULL;
+ restart = TRUE;
+
+ while (restart) {
+ restart = FALSE;
+
+ for (ins = bb->code; ins; ins = ins->next) {
+ switch (ins->opcode) {
+ case OP_STOREV_MEMBASE: {
+ src_var = get_vreg_to_inst (cfg, ins->sreg1);
+
+ if (!src_var) {
+ g_assert (ins->klass);
+ src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
+ }
+
+ EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
+
+ dreg = alloc_preg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
+ mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_assert (cfg->cbb == first_bb);
+
+ if (cfg->cbb->code || (cfg->cbb != first_bb)) {
+ /* Replace the original instruction with the new code sequence */
+
+ mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
+ first_bb->code = first_bb->last_ins = NULL;
+ first_bb->in_count = first_bb->out_count = 0;
+ cfg->cbb = first_bb;
+ }
+ else
+ prev = ins;
+ }
+ }
+
+ if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
+ }
+}
+
inline static MonoInst *
mono_get_domainvar (MonoCompile *cfg)
{
switch (ins->opcode) {
case OP_LDLEN:
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);
+ G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
MONO_ADD_INS (cfg->cbb, dest);
break;
case OP_BOUNDS_CHECK:
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_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
- ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
+ ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
break;
default:
break;
double vald;
} DVal;
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
/**
* mono_decompose_soft_float:
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);