#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
+#include <mono/arch/mips/mips-codegen.h>
+
#include "mini-mips.h"
#include "cpu-mips.h"
#include "trace.h"
#include "ir-emit.h"
-#warning "The mips backend is still being ported to the linear IR."
-
#define SAVE_FP_REGS 0
#define SAVE_ALL_REGS 0
#define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
-#define LONG_BRANCH 0 /* needed for yyparse in mcs */
#define SAVE_LMF 1
#define ALWAYS_USE_FP 1
#define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
+#define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
+#define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
+
+/* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
+#define mips_call(c,D,v) do { \
+ guint32 _target = (guint32)(v); \
+ if (1 || !(v) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
+ mips_load_const (c, D, _target); \
+ mips_jalr (c, D, mips_ra); \
+ } \
+ else { \
+ mips_jumpl (c, _target >> 2); \
+ } \
+ mips_nop (c); \
+ } while (0)
+
enum {
TLS_MODE_DETECT,
TLS_MODE_FAILED,
mono_bblock_add_inst (cfg->cbb, inst); \
} while (0)
-#define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) || ((ins)->opcode == OP_ICOMPARE)))
-#define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) || ((ins)->opcode == OP_ICOMPARE_IMM)))
+#define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
+ || ((ins)->opcode == OP_ICOMPARE) \
+ || ((ins)->opcode == OP_LCOMPARE)))
+#define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
+ || ((ins)->opcode == OP_ICOMPARE_IMM) \
+ || ((ins)->opcode == OP_LCOMPARE_IMM)))
#define INS_REWRITE(ins, op, _s1, _s2) do { \
int s1 = _s1; \
int fr;
gboolean gr_passed;
gboolean on_stack;
+ gboolean vtype_retaddr;
int stack_size;
guint32 stack_usage;
guint32 struct_ret;
void patch_lui_addiu(guint32 *ip, guint32 val);
guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
+guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
+void mips_adjust_stackframe(MonoCompile *cfg);
+void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
+MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+
void
mono_arch_flush_icache (guint8 *code, gint size)
mips_emit_exc_by_name(guint8 *code, const char *name)
{
guint32 addr;
+ MonoClass *exc_class;
- mips_load_const (code, mips_a0, name);
- addr = (guint32) mono_arch_get_throw_exception_by_name ();
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
+ g_assert (exc_class);
+ mips_load_const (code, mips_a0, exc_class->type_token);
+ addr = (guint32) mono_get_throw_corlib_exception ();
+ mips_call (code, mips_t9, addr);
return code;
}
guint8 *
-mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
+mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
{
- int br_offset = 5;
+ if (mips_is_imm16 (v))
+ mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
+ else {
+#if SIZEOF_REGISTER == 8
+ if (v != (long) v) {
+ /* v is not a sign-extended 32-bit value */
+ mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
+ mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
+ mips_dsll (code, dreg, dreg, 16);
+ mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
+ mips_dsll (code, dreg, dreg, 16);
+ mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
+ return code;
+ }
+#endif
+ if (((guint32)v) & (1 << 15)) {
+ mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
+ }
+ else {
+ mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
+ }
+ if (((guint32)v) & 0xffff)
+ mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
+ }
+ return code;
+}
+guint8 *
+mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
+{
g_assert (ins);
-#if LONG_BRANCH
- /* Invert test and emit branch around jump */
- switch (op) {
- case OP_MIPS_BEQ:
- mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BNE:
- mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BGEZ:
- mips_bltz (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BGTZ:
- mips_blez (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BLEZ:
- mips_bgtz (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- case OP_MIPS_BLTZ:
- mips_bgez (code, ins->sreg1, br_offset);
- mips_nop (code);
- break;
- default:
- g_assert_not_reached ();
- }
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code,
- MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
+ if (cfg->arch.long_branch) {
+ int br_offset = 5;
+
+ /* Invert test and emit branch around jump */
+ switch (op) {
+ case OP_MIPS_BEQ:
+ mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BNE:
+ mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGEZ:
+ mips_bltz (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGTZ:
+ mips_blez (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLEZ:
+ mips_bgtz (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLTZ:
+ mips_bgez (code, ins->sreg1, br_offset);
+ mips_nop (code);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
mono_add_patch_info (cfg, code - cfg->native_code,
MONO_PATCH_INFO_BB, ins->inst_true_bb);
- mips_lui (code, mips_at, mips_zero, 0);
- mips_addiu (code, mips_at, mips_at, 0);
- mips_jr (code, mips_at);
- mips_nop (code);
-#else
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code,
- MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
+ mips_lui (code, mips_at, mips_zero, 0);
+ mips_addiu (code, mips_at, mips_at, 0);
+ mips_jr (code, mips_at);
+ mips_nop (code);
+ }
+ else {
mono_add_patch_info (cfg, code - cfg->native_code,
MONO_PATCH_INFO_BB, ins->inst_true_bb);
- switch (op) {
- case OP_MIPS_BEQ:
- mips_beq (code, ins->sreg1, ins->sreg2, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BNE:
- mips_bne (code, ins->sreg1, ins->sreg2, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BGEZ:
- mips_bgez (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BGTZ:
- mips_bgtz (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BLEZ:
- mips_blez (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- case OP_MIPS_BLTZ:
- mips_bltz (code, ins->sreg1, 0);
- mips_nop (code);
- break;
- default:
- g_assert_not_reached ();
+ switch (op) {
+ case OP_MIPS_BEQ:
+ mips_beq (code, ins->sreg1, ins->sreg2, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BNE:
+ mips_bne (code, ins->sreg1, ins->sreg2, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGEZ:
+ mips_bgez (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BGTZ:
+ mips_bgtz (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLEZ:
+ mips_blez (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ case OP_MIPS_BLTZ:
+ mips_bltz (code, ins->sreg1, 0);
+ mips_nop (code);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
}
-#endif
return (code);
}
}
}
+#if 0
static int
offsets_from_pthread_key (guint32 key, int *offset2)
{
*offset2 = idx2 * sizeof (gpointer);
return 284 + idx1 * sizeof (gpointer);
}
+#endif
const char*
mono_arch_regname (int reg) {
+#if _MIPS_SIM == _ABIO32
static const char * rnames[] = {
"zero", "at", "v0", "v1",
"a0", "a1", "a2", "a3",
"t8", "t9", "k0", "k1",
"gp", "sp", "fp", "ra"
};
+#elif _MIPS_SIM == _ABIN32
+ static const char * rnames[] = {
+ "zero", "at", "v0", "v1",
+ "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7",
+ "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3",
+ "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1",
+ "gp", "sp", "fp", "ra"
+ };
+#endif
if (reg >= 0 && reg < 32)
return rnames [reg];
return "unknown";
gpointer
-mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
{
- /* FIXME: handle returning a struct */
- if (MONO_TYPE_ISSTRUCT (sig->ret))
- return (gpointer)regs [mips_a1];
+ g_assert(regs);
return (gpointer)regs [mips_a0];
}
switch (t->type) {
case MONO_TYPE_I4:
case MONO_TYPE_U4:
+#if (SIZEOF_REGISTER == 8)
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+#endif
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_PTR:
static void
args_onto_stack (CallInfo *info)
{
- g_assert(!info->on_stack);
- g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
+ g_assert (!info->on_stack);
+ g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
info->on_stack = TRUE;
info->stack_size = MIPS_STACK_PARAM_OFFSET;
}
+#if _MIPS_SIM == _ABIO32
/*
* O32 calling convention version
*/
/* Now, place the argument */
if (info->on_stack) {
- g_assert(info->stack_size % 4 == 0);
+ g_assert (info->stack_size % 4 == 0);
info->stack_size += (info->stack_size % 8);
ainfo->regtype = RegTypeBase;
}
info->stack_size += 8;
}
+#elif _MIPS_SIM == _ABIN32
+/*
+ * N32 calling convention version
+ */
+
+static void
+add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
+ /* First, see if we need to drop onto the stack */
+ if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
+
+ /* Now, place the argument */
+ if (info->on_stack) {
+ ainfo->regtype = RegTypeBase;
+ ainfo->reg = mips_sp; /* in the caller */
+ ainfo->offset = info->stack_size;
+ info->stack_size += SIZEOF_REGISTER;
+ }
+ else {
+ ainfo->regtype = RegTypeGeneral;
+ ainfo->reg = info->gr;
+ info->gr += 1;
+ info->gr_passed = TRUE;
+ }
+}
+
+static void
+add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
+ /* First, see if we need to drop onto the stack */
+ if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
+
+ /* Now, place the argument */
+ if (info->on_stack) {
+ g_assert (info->stack_size % 4 == 0);
+ info->stack_size += (info->stack_size % 8);
+
+ ainfo->regtype = RegTypeBase;
+ ainfo->reg = mips_sp; /* in the caller */
+ ainfo->offset = info->stack_size;
+ info->stack_size += SIZEOF_REGISTER;
+ }
+ else {
+ g_assert (info->gr <= MIPS_LAST_ARG_REG);
+
+ ainfo->regtype = RegTypeGeneral;
+ ainfo->reg = info->gr;
+ info->gr += 1;
+ info->gr_passed = TRUE;
+ }
+}
+
+static void
+add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
+ /* First, see if we need to drop onto the stack */
+ if (!info->on_stack) {
+ if (info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
+ else if (info->fr > MIPS_LAST_FPARG_REG)
+ args_onto_stack (info);
+ }
+
+ /* Now, place the argument */
+ if (info->on_stack) {
+ ainfo->regtype = RegTypeBase;
+ ainfo->reg = mips_sp; /* in the caller */
+ ainfo->offset = info->stack_size;
+ info->stack_size += FREG_SIZE;
+ }
+ else {
+ ainfo->regtype = RegTypeFP;
+ ainfo->reg = info->fr;
+ info->fr += 1;
+ /* FP and GP slots do not overlap */
+ info->gr += 1;
+ }
+}
+
+static void
+add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
+ /* First, see if we need to drop onto the stack */
+ if (!info->on_stack) {
+ if (info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
+ else if (info->fr > MIPS_LAST_FPARG_REG)
+ args_onto_stack (info);
+ }
+
+ /* Now, place the argument */
+ if (info->on_stack) {
+ g_assert(info->stack_size % 4 == 0);
+ info->stack_size += (info->stack_size % 8);
+
+ ainfo->regtype = RegTypeBase;
+ ainfo->reg = mips_sp; /* in the caller */
+ ainfo->offset = info->stack_size;
+ info->stack_size += FREG_SIZE;
+ }
+ else {
+ ainfo->regtype = RegTypeFP;
+ ainfo->reg = info->fr;
+ info->fr += 1;
+ /* FP and GP slots do not overlap */
+ info->gr += 1;
+ }
+}
+#endif
static CallInfo*
calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
{
guint i;
int n = sig->hasthis + sig->param_count;
- guint32 simpletype;
+ int pstart;
+ MonoType* simpletype;
CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
cinfo->fr = MIPS_FIRST_FPARG_REG;
DEBUG(printf("calculate_sizes\n"));
+ cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
+ pstart = 0;
+ n = 0;
+#if 0
/* handle returning a struct */
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
cinfo->struct_ret = cinfo->gr;
add_int32_arg (cinfo, &cinfo->ret);
}
- n = 0;
if (sig->hasthis) {
add_int32_arg (cinfo, cinfo->args + n);
n++;
}
+#else
+ /*
+ * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
+ * the first argument, allowing 'this' to be always passed in the first arg reg.
+ * Also do this if the first argument is a reference type, since virtual calls
+ * are sometimes made using calli without sig->hasthis set, like in the delegate
+ * invoke wrappers.
+ */
+ if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, sig->params [0]))))) {
+ if (sig->hasthis) {
+ add_int32_arg (cinfo, cinfo->args + n);
+ n ++;
+ } else {
+ add_int32_arg (cinfo, cinfo->args + sig->hasthis);
+ pstart = 1;
+ n ++;
+ }
+ add_int32_arg (cinfo, &cinfo->ret);
+ cinfo->struct_ret = cinfo->ret.reg;
+ } else {
+ /* this */
+ if (sig->hasthis) {
+ add_int32_arg (cinfo, cinfo->args + n);
+ n ++;
+ }
+
+ if (cinfo->vtype_retaddr) {
+ add_int32_arg (cinfo, &cinfo->ret);
+ cinfo->struct_ret = cinfo->ret.reg;
+ }
+ }
+#endif
+
DEBUG(printf("params: %d\n", sig->param_count));
- for (i = 0; i < sig->param_count; ++i) {
+ for (i = pstart; i < sig->param_count; ++i) {
if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
/* Prevent implicit arguments and sig_cookie from
being passed in registers */
n++;
continue;
}
- simpletype = mono_type_get_underlying_type (sig->params [i])->type;
- switch (simpletype) {
+ simpletype = mono_type_get_underlying_type (sig->params [i]);
+ switch (simpletype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
n++;
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+ if (!mono_type_generic_inst_is_valuetype (simpletype)) {
cinfo->args [n].size = sizeof (gpointer);
add_int32_arg (cinfo, &cinfo->args[n]);
n++;
cinfo->stack_size, alignment);
#endif
nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
- g_assert(cinfo->args [n].size == 0);
- g_assert(cinfo->args [n].vtsize == 0);
+ g_assert (cinfo->args [n].size == 0);
+ g_assert (cinfo->args [n].vtsize == 0);
for (j = 0; j < nwords; ++j) {
if (j == 0) {
add_int32_arg (cinfo, &cinfo->args [n]);
}
{
- simpletype = mono_type_get_underlying_type (sig->ret)->type;
- switch (simpletype) {
+ simpletype = mono_type_get_underlying_type (sig->ret);
+ switch (simpletype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
cinfo->ret.regtype = RegTypeFP;
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
+ if (!mono_type_generic_inst_is_valuetype (simpletype)) {
cinfo->ret.reg = mips_v0;
break;
}
int i, offset, size, align, curinst;
int frame_reg = mips_sp;
guint32 iregs_to_save = 0;
+#if SAVE_FP_REGS
guint32 fregs_to_restore;
+#endif
/* spill down, we'll fix it in a separate pass */
// cfg->flags |= MONO_CFG_HAS_SPILLUP;
/* a0-a3 always present */
cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
- header = mono_method_get_header (cfg->method);
+ header = cfg->header;
sig = mono_method_signature (cfg->method);
switch (mono_type_get_underlying_type (sig->ret)->type) {
case MONO_TYPE_VOID:
break;
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ cfg->ret->opcode = OP_REGVAR;
+ cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
+ break;
default:
cfg->ret->opcode = OP_REGVAR;
cfg->ret->inst_c0 = mips_v0;
* pinvoke wrappers when they call functions returning structure
*/
if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
- size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
+ size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
else
size = mono_type_size (inst->inst_vtype, &align);
if (iregs_to_save) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_save & (1 << i)) {
- offset += sizeof (gulong);
+ offset += SIZEOF_REGISTER;
}
}
}
if (fregs_to_restore) {
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
if (fregs_to_restore & (1 << i)) {
- offset += sizeof (double);
+ offset += sizeof(double);
}
}
}
#endif
+#if _MIPS_SIM == _ABIO32
/* Now add space for saving the ra */
- offset += 4;
+ offset += SIZEOF_VOID_P;
/* change sign? */
offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
cfg->stack_offset = offset;
cfg->arch.local_alloc_offset = cfg->stack_offset;
+#endif
/*
* Now allocate stack slots for the int arg regs (a0 - a3)
cfg->vret_addr->inst_c0 = mips_a0;
cfg->vret_addr->inst_offset = offset;
cfg->vret_addr->inst_basereg = frame_reg;
- offset += 4;
+ offset += SIZEOF_REGISTER;
}
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
inst->opcode = OP_REGOFFSET;
size = mono_type_size (arg_type, &align);
- if (size < 4) {
- size = 4;
- align = 4;
+ if (size < SIZEOF_REGISTER) {
+ size = SIZEOF_REGISTER;
+ align = SIZEOF_REGISTER;
}
inst->inst_basereg = frame_reg;
offset = (offset + align - 1) & ~(align - 1);
// g_print ("allocating param %d to %d\n", i, inst->inst_offset);
}
else {
- /* Even a0-a3 get stack slots */
- size = sizeof (gpointer);
- align = sizeof (gpointer);
+#if _MIPS_SIM == _ABIO32
+ /* o32: Even a0-a3 get stack slots */
+ size = SIZEOF_REGISTER;
+ align = SIZEOF_REGISTER;
inst->inst_basereg = frame_reg;
offset = (offset + align - 1) & ~(align - 1);
inst->inst_offset = offset;
if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
cfg->sig_cookie += size;
// g_print ("allocating param %d to %d\n", i, inst->inst_offset);
+#endif
}
}
+#if _MIPS_SIM == _ABIN32
+ /* Now add space for saving the ra */
+ offset += SIZEOF_VOID_P;
+
+ /* change sign? */
+ offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
+ cfg->stack_offset = offset;
+ cfg->arch.local_alloc_offset = cfg->stack_offset;
+#endif
}
void
}
in = call->args [i];
if (ainfo->regtype == RegTypeGeneral) {
+#if SIZEOF_REGISTER == 4
if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
MONO_INST_NEW (cfg, ins, OP_MOVE);
ins->dreg = mono_alloc_ireg (cfg);
ins->sreg1 = in->dreg + 2;
MONO_ADD_INS (cfg->cbb, ins);
mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
- } else if (!t->byref && (t->type == MONO_TYPE_R4)) {
+ } else
+#endif
+ if (!t->byref && (t->type == MONO_TYPE_R4)) {
int freg;
+#if PROMOTE_R4_TO_R8
/* ??? - convert to single first? */
MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
ins->dreg = mono_alloc_freg (cfg);
ins->sreg1 = in->dreg;
MONO_ADD_INS (cfg->cbb, ins);
freg = ins->dreg;
-
+#else
+ freg = in->dreg;
+#endif
/* trying to load float value into int registers */
MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
ins->dreg = mono_alloc_ireg (cfg);
int dreg = mono_alloc_freg (cfg);
if (ainfo->size == 4) {
- MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
} else {
MONO_INST_NEW (cfg, ins, OP_FMOVE);
ins->dreg = dreg;
#endif
call->stack_usage = cinfo->stack_usage;
cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
- cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
+#if _MIPS_SIM == _ABIO32
+ /* a0-a3 always present */
+ cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
+#endif
cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
cfg->flags |= MONO_CFG_HAS_CALLS;
/*
dreg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
- soffset += sizeof (gpointer);
+ soffset += SIZEOF_REGISTER;
}
if (ovf_size != 0) {
- mini_emit_memcpy (cfg, mips_fp, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+ mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
}
} else if (ainfo->regtype == RegTypeFP) {
int tmpr = mono_alloc_freg (cfg);
mono_method_signature (method)->ret);
if (!ret->byref) {
+#if (SIZEOF_REGISTER == 4)
if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
MonoInst *ins;
MONO_ADD_INS (cfg->cbb, ins);
return;
}
- if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
+#endif
+ if (ret->type == MONO_TYPE_R8) {
MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
return;
}
+ if (ret->type == MONO_TYPE_R4) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
+ return;
+ }
}
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
}
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LADD_IMM:
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LSUB:
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LSUB_IMM:
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LMUL:
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
#if 0
/* Now, if (tmp4 == 0) then overflow */
MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LADD_OVF_UN:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+ MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
+ NULLIFY_INS(ins);
+ break;
+
case OP_LMUL_OVF:
case OP_LMUL_OVF_UN:
mono_print_ins (ins);
/* Now, if (tmp4 == 1) then overflow */
MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
case OP_LSUB_OVF_UN:
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
#if 0
case OP_LCONV_TO_OVF_I1_UN:
case OP_LBGT_UN:
case OP_LBLE_UN:
case OP_LBLT_UN:
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+#if 0
case OP_LCONV_TO_R8_2:
case OP_LCONV_TO_R4_2:
case OP_LCONV_TO_R_UN_2:
+#endif
case OP_LCONV_TO_OVF_I4_2:
- case OP_LMIN_UN:
+ tmp1 = mono_alloc_ireg (cfg);
+
+ /* Overflows if reg2 != sign extension of reg1 */
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
+ NULLIFY_INS(ins);
+ break;
+
+ case OP_LMIN_UN:
case OP_LMAX_UN:
case OP_LMIN:
case OP_LMAX:
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
- /* Now, if (tmp4 == 0) then overflow */
+ /* Now, if (tmp5 == 0) then overflow */
MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
+ /* Make decompse and method-to-ir.c happy, last insn writes dreg */
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
+ NULLIFY_INS(ins);
+ break;
+
+ case OP_IADD_OVF_UN:
+ tmp1 = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
+ /* Make decompse and method-to-ir.c happy, last insn writes dreg */
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
+ NULLIFY_INS(ins);
break;
case OP_ISUB_OVF:
MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
+ /* Make decompse and method-to-ir.c happy, last insn writes dreg */
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
+ NULLIFY_INS(ins);
break;
case OP_ISUB_OVF_UN:
MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
- ins->opcode = OP_NOP;
- break;
-
- case OP_ICONV_TO_R_UN: {
- static const guint64 adjust_val = 0x4330000000000000ULL;
- int msw_reg = mono_alloc_ireg (cfg);
- int adj_reg = mono_alloc_freg (cfg);
- int tmp_reg = mono_alloc_freg (cfg);
- int basereg = mips_sp;
- int offset = -8;
-
- MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
- if (!mips_is_imm16 (offset + 4)) {
- basereg = mono_alloc_ireg (cfg);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
- }
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
- MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
- MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
- ins->opcode = OP_NOP;
- break;
- }
- case OP_ICONV_TO_R4:
- case OP_ICONV_TO_R8: {
- /* FIXME: change precision for OP_ICONV_TO_R4 */
- static const guint64 adjust_val = 0x4330000080000000ULL;
- int msw_reg = mono_alloc_ireg (cfg);
- int xored = mono_alloc_ireg (cfg);
- int adj_reg = mono_alloc_freg (cfg);
- int tmp_reg = mono_alloc_freg (cfg);
- int basereg = mips_sp;
- int offset = -8;
-
- if (!mips_is_imm16 (offset + 4)) {
- basereg = mono_alloc_ireg (cfg);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
- }
- MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
- MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
- MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
- if (ins->opcode == OP_ICONV_TO_R4)
- MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
- ins->opcode = OP_NOP;
+ /* Make decompse and method-to-ir.c happy, last insn writes dreg */
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
+ NULLIFY_INS(ins);
break;
}
-#if 0
- case OP_CKFINITE: {
- int msw_reg = mono_alloc_ireg (cfg);
- int basereg = mips_sp;
- int offset = -8;
-
- if (!mips_is_imm16 (offset + 4)) {
- basereg = mono_alloc_ireg (cfg);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
- }
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
- MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
- MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
- MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
- ins->opcode = OP_NOP;
- break;
- }
-#endif
- }
-
}
static int
return OP_COMPARE;
case OP_ICOMPARE_IMM:
return OP_ICOMPARE;
+ case OP_LCOMPARE_IMM:
+ return OP_LCOMPARE;
case OP_ADDCC_IMM:
return OP_IADDCC;
case OP_ADC_IMM:
return OP_STOREI2_MEMBASE_REG;
case OP_STOREI4_MEMBASE_IMM:
return OP_STOREI4_MEMBASE_REG;
+ case OP_STOREI8_MEMBASE_IMM:
+ return OP_STOREI8_MEMBASE_REG;
}
return mono_op_imm_to_op (op);
}
MONO_BB_FOR_EACH_INS (bb, ins) {
loop_start:
switch (ins->opcode) {
+ case OP_COMPARE:
+ case OP_ICOMPARE:
+ case OP_LCOMPARE:
+ next = ins->next;
+ /* Branch opts can eliminate the branch */
+ if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
+ NULLIFY_INS(ins);
+ break;
+ }
+ break;
+
case OP_COMPARE_IMM:
case OP_ICOMPARE_IMM:
+ case OP_LCOMPARE_IMM:
next = ins->next;
/* Branch opts can eliminate the branch */
if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
- ins->opcode = OP_NOP;
+ NULLIFY_INS(ins);
break;
}
if (ins->inst_imm) {
ins->opcode = OP_COMPARE;
else if (ins->opcode == OP_ICOMPARE_IMM)
ins->opcode = OP_ICOMPARE;
+ else if (ins->opcode == OP_LCOMPARE_IMM)
+ ins->opcode = OP_LCOMPARE;
goto loop_start;
case OP_IDIV_UN_IMM:
}
break;
- case OP_FCOMPARE:
- next = ins->next;
- /* Branch opts can eliminate the branch */
- if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
- ins->opcode = OP_NOP;
- break;
- }
- g_assert(next);
-
- /*
- * remap compare/branch and compare/set
- * to MIPS specific opcodes.
- */
- ins->opcode = OP_NOP;
- next->opcode = map_to_mips_op (next->opcode);
- next->sreg1 = ins->sreg1;
- next->sreg2 = ins->sreg2;
- break;
-
case OP_SUB_IMM:
+ case OP_ISUB_IMM:
if (!mips_is_imm16 (-ins->inst_imm)) {
NEW_INS (cfg, last_ins, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
}
break;
- case OP_SBB_IMM:
- case OP_SUBCC_IMM:
- case OP_ADC_IMM:
- NEW_INS (cfg, last_ins, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_alloc_ireg (cfg);
- ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
- break;
-
case OP_MUL_IMM:
+ case OP_IMUL_IMM:
if (ins->inst_imm == 1) {
ins->opcode = OP_MOVE;
break;
ins->inst_imm = imm;
break;
}
- if (!mips_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, last_ins, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_alloc_ireg (cfg);
- ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
- }
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
+ temp->inst_c0 = ins->inst_imm;
+ temp->dreg = mono_alloc_ireg (cfg);
+ ins->sreg2 = temp->dreg;
+ ins->opcode = map_to_reg_reg_op (ins->opcode);
+ break;
+
+ case OP_LOCALLOC_IMM:
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
+ temp->inst_c0 = ins->inst_imm;
+ temp->dreg = mono_alloc_ireg (cfg);
+ ins->sreg1 = temp->dreg;
+ ins->opcode = OP_LOCALLOC;
break;
case OP_LOAD_MEMBASE:
case OP_STOREI1_MEMBASE_IMM:
case OP_STOREI2_MEMBASE_IMM:
case OP_STOREI4_MEMBASE_IMM:
+ case OP_STOREI8_MEMBASE_IMM:
if (!ins->inst_imm) {
ins->sreg1 = mips_zero;
ins->opcode = map_to_reg_reg_op (ins->opcode);
}
break;
+ case OP_FCOMPARE:
+ next = ins->next;
+ /* Branch opts can eliminate the branch */
+ if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
+ NULLIFY_INS(ins);
+ break;
+ }
+ g_assert(next);
+
+ /*
+ * remap compare/branch and compare/set
+ * to MIPS specific opcodes.
+ */
+ next->opcode = map_to_mips_op (next->opcode);
+ next->sreg1 = ins->sreg1;
+ next->sreg2 = ins->sreg2;
+ NULLIFY_INS(ins);
+ break;
+
+#if 0
case OP_R8CONST:
case OP_R4CONST:
NEW_INS (cfg, last_ins, temp, OP_ICONST);
* later optimize to use lis + load_membase
*/
goto loop_start;
-
+#endif
case OP_IBEQ:
g_assert (ins_is_compare(last_ins));
INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
- last_ins->opcode = OP_NOP;
+ NULLIFY_INS(last_ins);
break;
case OP_IBNE_UN:
g_assert (ins_is_compare(last_ins));
INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
- last_ins->opcode = OP_NOP;
+ NULLIFY_INS(last_ins);
break;
case OP_IBGE:
case OP_CLT:
case OP_ICLT:
INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
- last_ins->opcode = OP_NOP;
+ NULLIFY_INS(last_ins);
break;
case OP_CLT_UN:
case OP_ICLT_UN:
INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
- last_ins->opcode = OP_NOP;
+ NULLIFY_INS(last_ins);
break;
case OP_CGT:
case OP_COND_EXC_GE_UN:
case OP_COND_EXC_IGE_UN:
g_assert (ins_is_compare(last_ins));
- INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
MONO_DELETE_INS(bb, last_ins);
break;
case OP_COND_EXC_GT_UN:
case OP_COND_EXC_IGT_UN:
g_assert (ins_is_compare(last_ins));
- INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
MONO_DELETE_INS(bb, last_ins);
break;
case OP_COND_EXC_LT_UN:
case OP_COND_EXC_ILT_UN:
g_assert (ins_is_compare(last_ins));
- INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
MONO_DELETE_INS(bb, last_ins);
break;
static guchar*
emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
{
- /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
+ /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
#if 1
mips_truncwd (code, mips_ftemp, sreg);
#else
/*
* emit_load_volatile_arguments:
*
- * Load volatile arguments from the stack to the original input registers.
+ * Load volatile arguments from the stack to the original input registers.
* Required before a tail call.
*/
static guint8 *
inst = cfg->args [i];
if (inst->opcode == OP_REGVAR) {
if (ainfo->regtype == RegTypeGeneral)
- mips_move (code, ainfo->reg, inst->dreg);
+ MIPS_MOVE (code, ainfo->reg, inst->dreg);
else if (ainfo->regtype == RegTypeFP)
g_assert_not_reached();
else if (ainfo->regtype == RegTypeBase) {
/* do nothing */
} else if (ainfo->regtype == RegTypeFP) {
g_assert (mips_is_imm16 (inst->inst_offset));
- if (ainfo->size == 8)
+ if (ainfo->size == 8) {
+#if _MIPS_SIM == _ABIO32
+ mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
+ mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
+#elif _MIPS_SIM == _ABIN32
mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+#endif
+ }
else if (ainfo->size == 4)
mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
else
g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
for (i = 0; i < ainfo->size; ++i) {
mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
- doffset += sizeof (gpointer);
+ doffset += SIZEOF_REGISTER;
}
} else if (ainfo->regtype == RegTypeStructByAddr) {
g_assert (mips_is_imm16 (inst->inst_offset));
mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
}
break;
+ case OP_STOREI8_MEMBASE_IMM:
+ mips_load_const (code, mips_temp, ins->inst_imm);
+ if (mips_is_imm16 (ins->inst_offset)) {
+ mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
+ } else {
+ mips_load_const (code, mips_at, ins->inst_offset);
+ mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
+ }
+ break;
case OP_STORE_MEMBASE_IMM:
case OP_STOREI4_MEMBASE_IMM:
mips_load_const (code, mips_temp, ins->inst_imm);
mips_sw (code, ins->sreg1, mips_at, 0);
}
break;
+ case OP_STOREI8_MEMBASE_REG:
+ if (mips_is_imm16 (ins->inst_offset)) {
+ mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+ } else {
+ mips_load_const (code, mips_at, ins->inst_offset);
+ mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
+ mips_sd (code, ins->sreg1, mips_at, 0);
+ }
+ break;
case OP_LOADU4_MEM:
g_assert_not_reached ();
//x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
//x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
break;
+ case OP_LOADI8_MEMBASE:
+ if (mips_is_imm16 (ins->inst_offset)) {
+ mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+ } else {
+ mips_load_const (code, mips_at, ins->inst_offset);
+ mips_addu (code, mips_at, mips_at, ins->inst_basereg);
+ mips_ld (code, ins->dreg, mips_at, 0);
+ }
+ break;
case OP_LOAD_MEMBASE:
case OP_LOADI4_MEMBASE:
case OP_LOADU4_MEMBASE:
+ g_assert (ins->dreg != -1);
if (mips_is_imm16 (ins->inst_offset)) {
mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
} else {
case OP_IADD:
mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_LADD:
+ mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
+ break;
+
case OP_ADD_IMM:
case OP_IADD_IMM:
- if (mips_is_imm16 (ins->inst_imm)) {
- mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
- } else {
- mips_load_const (code, mips_at, ins->inst_imm);
- mips_addu (code, ins->dreg, ins->sreg1, mips_at);
- }
+ g_assert (mips_is_imm16 (ins->inst_imm));
+ mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
+ case OP_LADD_IMM:
+ g_assert (mips_is_imm16 (ins->inst_imm));
+ mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
+ break;
+
case OP_ISUB:
mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_LSUB:
+ mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
+ break;
+
case OP_ISUB_IMM:
case OP_SUB_IMM:
// we add the negated value
- if (mips_is_imm16 (-ins->inst_imm))
- mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
- else {
- mips_load_const (code, mips_at, ins->inst_imm);
- mips_subu (code, ins->dreg, ins->sreg1, mips_at);
- }
+ g_assert (mips_is_imm16 (-ins->inst_imm));
+ mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
break;
+
+ case OP_LSUB_IMM:
+ // we add the negated value
+ g_assert (mips_is_imm16 (-ins->inst_imm));
+ mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
+ break;
+
case OP_IAND:
+ case OP_LAND:
mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+
case OP_AND_IMM:
case OP_IAND_IMM:
- if (mips_is_imm16 (ins->inst_imm)) {
- mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
- } else {
- mips_load_const (code, mips_at, ins->inst_imm);
- mips_and (code, ins->dreg, ins->sreg1, mips_at);
- }
+ case OP_LAND_IMM:
+ g_assert (!(ins->inst_imm & 0xffff0000));
+ mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
+
case OP_IDIV:
case OP_IREM: {
guint32 *divisor_is_m1;
+ guint32 *dividend_is_minvalue;
guint32 *divisor_is_zero;
- /* */
- mips_addiu (code, mips_at, mips_zero, 0xffff);
- divisor_is_m1 = (guint32 *)code;
+ mips_load_const (code, mips_at, -1);
+ divisor_is_m1 = (guint32 *)(void *)code;
mips_bne (code, ins->sreg2, mips_at, 0);
+ mips_lui (code, mips_at, mips_zero, 0x8000);
+ dividend_is_minvalue = (guint32 *)(void *)code;
+ mips_bne (code, ins->sreg1, mips_at, 0);
mips_nop (code);
- /* Divide by -1 -- throw exception */
- EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
+ /* Divide Int32.MinValue by -1 -- throw exception */
+ EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
mips_patch (divisor_is_m1, (guint32)code);
+ mips_patch (dividend_is_minvalue, (guint32)code);
/* Put divide in branch delay slot (NOT YET) */
- divisor_is_zero = (guint32 *)code;
+ divisor_is_zero = (guint32 *)(void *)code;
mips_bne (code, ins->sreg2, mips_zero, 0);
mips_nop (code);
mips_patch (divisor_is_zero, (guint32)code);
mips_divu (code, ins->sreg1, ins->sreg2);
- if (ins->opcode == OP_IDIV)
+ if (ins->opcode == OP_IDIV_UN)
mips_mflo (code, ins->dreg);
else
mips_mfhi (code, ins->dreg);
case OP_OR_IMM:
case OP_IOR_IMM:
g_assert (!(ins->inst_imm & 0xffff0000));
- mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
+ mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
case OP_IXOR:
mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
case OP_ISHR:
mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_LSHR:
+ mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
+ break;
case OP_SHR_IMM:
case OP_ISHR_IMM:
mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
break;
+ case OP_LSHR_IMM:
+ mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
+ break;
case OP_SHR_UN_IMM:
case OP_ISHR_UN_IMM:
mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
break;
+ case OP_LSHR_UN_IMM:
+ mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
+ break;
case OP_ISHR_UN:
mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_LSHR_UN:
+ mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
+ break;
case OP_INOT:
+ case OP_LNOT:
mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
break;
case OP_INEG:
mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
break;
+ case OP_LNEG:
+ mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
+ break;
case OP_IMUL:
-#if 1
+#if USE_MUL
mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
#else
mips_mult (code, ins->sreg1, ins->sreg2);
mips_nop (code);
#endif
break;
- case OP_MUL_IMM:
- case OP_IMUL_IMM:
- mips_load_const (code, mips_at, ins->inst_imm);
-#if 1
- mips_mul (code, ins->dreg, ins->sreg1, mips_at);
-#else
- mips_mult (code, ins->sreg1, mips_at);
+#if SIZEOF_REGISTER == 8
+ case OP_LMUL:
+ mips_dmult (code, ins->sreg1, ins->sreg2);
mips_mflo (code, ins->dreg);
- mips_nop (code);
- mips_nop (code);
-#endif
break;
+#endif
case OP_IMUL_OVF: {
guint32 *patch;
mips_mult (code, ins->sreg1, ins->sreg2);
mips_patch (patch, (guint32)code);
break;
}
- case OP_IMUL_OVF_UN:
-#if 0
- mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
-#else
+ case OP_IMUL_OVF_UN: {
+ guint32 *patch;
mips_mult (code, ins->sreg1, ins->sreg2);
mips_mflo (code, ins->dreg);
mips_mfhi (code, mips_at);
mips_nop (code);
mips_nop (code);
-#endif
- /* XXX - Throw exception if we overflowed */
+ patch = (guint32 *)(void *)code;
+ mips_beq (code, mips_at, mips_zero, 0);
+ mips_nop (code);
+ EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
+ mips_patch (patch, (guint32)code);
break;
+ }
case OP_ICONST:
mips_load_const (code, ins->dreg, ins->inst_c0);
break;
+#if SIZEOF_REGISTER == 8
+ case OP_I8CONST:
+ mips_load_const (code, ins->dreg, ins->inst_c0);
+ break;
+#endif
case OP_AOTCONST:
mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
mips_load (code, ins->dreg, 0);
case OP_MIPS_MTC1S:
mips_mtc1 (code, ins->dreg, ins->sreg1);
break;
+ case OP_MIPS_MTC1S_2:
+ mips_mtc1 (code, ins->dreg, ins->sreg1);
+ mips_mtc1 (code, ins->dreg+1, ins->sreg2);
+ break;
case OP_MIPS_MFC1S:
mips_mfc1 (code, ins->dreg, ins->sreg1);
break;
mips_dmtc1 (code, ins->dreg, ins->sreg1);
break;
case OP_MIPS_MFC1D:
+#if 0
mips_dmfc1 (code, ins->dreg, ins->sreg1);
+#else
+ mips_mfc1 (code, ins->dreg+1, ins->sreg1);
+ mips_mfc1 (code, ins->dreg, ins->sreg1+1);
+#endif
break;
case OP_ICONV_TO_I4:
case OP_ICONV_TO_U4:
case OP_MOVE:
if (ins->dreg != ins->sreg1)
- mips_move (code, ins->dreg, ins->sreg1);
+ MIPS_MOVE (code, ins->dreg, ins->sreg1);
+ break;
+#if SIZEOF_REGISTER == 8
+ case OP_ZEXT_I4:
+ mips_dsll (code, ins->dreg, ins->sreg1, 32);
+ mips_dsrl (code, ins->dreg, ins->dreg, 32);
+ break;
+ case OP_SEXT_I4:
+ mips_dsll (code, ins->dreg, ins->sreg1, 32);
+ mips_dsra (code, ins->dreg, ins->dreg, 32);
break;
+#endif
case OP_SETLRET:
/* Get sreg1 into v1, sreg2 into v0 */
if (ins->sreg1 == mips_v0) {
if (ins->sreg1 != mips_at)
- mips_move (code, mips_at, ins->sreg1);
+ MIPS_MOVE (code, mips_at, ins->sreg1);
if (ins->sreg2 != mips_v0)
- mips_move (code, mips_v0, ins->sreg2);
- mips_move (code, mips_v1, mips_at);
+ MIPS_MOVE (code, mips_v0, ins->sreg2);
+ MIPS_MOVE (code, mips_v1, mips_at);
}
else {
if (ins->sreg2 != mips_v0)
- mips_move (code, mips_v0, ins->sreg2);
+ MIPS_MOVE (code, mips_v0, ins->sreg2);
if (ins->sreg1 != mips_v1)
- mips_move (code, mips_v1, ins->sreg1);
+ MIPS_MOVE (code, mips_v1, ins->sreg1);
}
break;
case OP_FMOVE:
mips_cvtsd (code, ins->dreg, ins->sreg1);
break;
case OP_FCONV_TO_R4:
- /* Convert from double to float and back again */
+#if 0
mips_cvtsd (code, ins->dreg, ins->sreg1);
- mips_cvtds (code, ins->dreg, ins->dreg);
+#else
+ /* Just a move, no precision change */
+ if (ins->dreg != ins->sreg1) {
+ mips_fmovd (code, ins->dreg, ins->sreg1);
+ }
+#endif
break;
case OP_JMP:
code = emit_load_volatile_arguments(cfg, code);
mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
-#if LONG_BRANCH
- mips_lui (code, mips_t9, mips_zero, 0);
- mips_addiu (code, mips_t9, mips_t9, 0);
- mips_jr (code, mips_t9);
- mips_nop (code);
-#else
- mips_beq (code, mips_zero, mips_zero, 0);
- mips_nop (code);
-#endif
+ if (cfg->arch.long_branch) {
+ mips_lui (code, mips_t9, mips_zero, 0);
+ mips_addiu (code, mips_t9, mips_t9, 0);
+ mips_jr (code, mips_t9);
+ mips_nop (code);
+ }
+ else {
+ mips_beq (code, mips_zero, mips_zero, 0);
+ mips_nop (code);
+ }
break;
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
case OP_VCALL2:
case OP_VOIDCALL:
case OP_CALL:
- if (ins->flags & MONO_INST_HAS_METHOD)
+ if (ins->flags & MONO_INST_HAS_METHOD) {
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
- else
+ mips_call (code, mips_t9, call->method);
+ }
+ else {
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
- mips_lui (code, mips_t9, mips_zero, 0);
- mips_addiu (code, mips_t9, mips_t9, 0);
+ mips_call (code, mips_t9, call->fptr);
+ }
break;
case OP_FCALL_REG:
case OP_LCALL_REG:
case OP_VCALL2_REG:
case OP_VOIDCALL_REG:
case OP_CALL_REG:
- mips_move (code, mips_t9, ins->sreg1);
+ MIPS_MOVE (code, mips_t9, ins->sreg1);
+ mips_jalr (code, mips_t9, mips_ra);
+ mips_nop (code);
break;
case OP_FCALL_MEMBASE:
case OP_LCALL_MEMBASE:
case OP_VOIDCALL_MEMBASE:
case OP_CALL_MEMBASE:
mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
+ mips_jalr (code, mips_t9, mips_ra);
+ mips_nop (code);
break;
}
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+#if PROMOTE_R4_TO_R8
+ /* returned an FP R4 (single), promote to R8 (double) in place */
if ((ins->opcode == OP_FCALL ||
ins->opcode == OP_FCALL_REG) &&
call->signature->ret->type == MONO_TYPE_R4) {
mips_cvtds (code, mips_f0, mips_f0);
}
+#endif
break;
case OP_LOCALLOC: {
int area_offset = cfg->param_area;
/* Round up ins->sreg1, mips_at ends up holding size */
mips_addiu (code, mips_at, ins->sreg1, 31);
- mips_andi (code, mips_at, mips_at, ~31);
+ mips_addiu (code, mips_temp, mips_zero, ~31);
+ mips_and (code, mips_at, mips_at, mips_temp);
mips_subu (code, mips_sp, mips_sp, mips_at);
+ g_assert (mips_is_imm16 (area_offset));
mips_addiu (code, ins->dreg, mips_sp, area_offset);
if (ins->flags & MONO_INST_INIT) {
mips_move (code, mips_temp, ins->dreg);
mips_sb (code, mips_zero, mips_temp, 0);
mips_addiu (code, mips_at, mips_at, -1);
- mips_bne (code, mips_at, mips_zero, -4);
+ mips_bne (code, mips_at, mips_zero, -3);
mips_addiu (code, mips_temp, mips_temp, 1);
}
break;
}
case OP_THROW: {
- gpointer addr = mono_arch_get_throw_exception();
+ gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
mips_move (code, mips_a0, ins->sreg1);
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, addr);
mips_break (code, 0xfc);
break;
}
case OP_RETHROW: {
- gpointer addr = mono_arch_get_rethrow_exception();
+ gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
mips_move (code, mips_a0, ins->sreg1);
- mips_load_const (code, mips_t9, addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, addr);
mips_break (code, 0xfb);
break;
}
code = emit_unreserve_param_area (cfg, code);
if (ins->sreg1 != mips_v0)
- mips_move (code, mips_v0, ins->sreg1);
+ MIPS_MOVE (code, mips_v0, ins->sreg1);
if (mips_is_imm16 (spvar->inst_offset)) {
mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
} else {
mips_addiu (code, mips_t9, mips_t9, 0);
mips_jalr (code, mips_t9, mips_ra);
mips_nop (code);
+ /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
+ mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
break;
case OP_LABEL:
ins->inst_c0 = code - cfg->native_code;
break;
case OP_BR:
- if (ins->flags & MONO_INST_BRLABEL) {
- mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- } else {
- mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
+ mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
+ if (cfg->arch.long_branch) {
+ mips_lui (code, mips_at, mips_zero, 0);
+ mips_addiu (code, mips_at, mips_at, 0);
+ mips_jr (code, mips_at);
+ mips_nop (code);
+ }
+ else {
+ mips_beq (code, mips_zero, mips_zero, 0);
+ mips_nop (code);
}
-#if LONG_BRANCH
- mips_lui (code, mips_at, mips_zero, 0);
- mips_addiu (code, mips_at, mips_at, 0);
- mips_jr (code, mips_at);
- mips_nop (code);
-#else
- mips_beq (code, mips_zero, mips_zero, 0);
- mips_nop (code);
-#endif
break;
case OP_BR_REG:
mips_jr (code, ins->sreg1);
g_assert (ins->sreg1 != -1);
mips_sll (code, mips_at, ins->sreg1, 2);
if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
- mips_move (code, mips_t8, mips_ra);
+ MIPS_MOVE (code, mips_t8, mips_ra);
mips_bgezal (code, mips_zero, 1); /* bal */
mips_nop (code);
mips_addu (code, mips_t9, mips_ra, mips_at);
/* Table is 16 or 20 bytes from target of bal above */
if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
- mips_move (code, mips_ra, mips_t8);
+ MIPS_MOVE (code, mips_ra, mips_t8);
mips_lw (code, mips_t9, mips_t9, 20);
}
else
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_beq (code, mips_at, mips_zero, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_CLT:
case OP_CLT_UN:
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_bltz (code, mips_at, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_CGT:
case OP_CGT_UN:
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_bgtz (code, mips_at, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_MIPS_COND_EXC_EQ:
break;
case OP_MIPS_COND_EXC_LE_UN:
- mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
+ mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
throw = (guint32 *)(void *)code;
- mips_blez (code, mips_at, 0);
+ mips_beq (code, mips_at, mips_zero, 0);
mips_nop (code);
break;
mips_nop (code);
break;
+ case OP_MIPS_COND_EXC_GT_UN:
+ mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
+ throw = (guint32 *)(void *)code;
+ mips_bne (code, mips_at, mips_zero, 0);
+ mips_nop (code);
+ break;
+
case OP_MIPS_COND_EXC_LT:
mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
throw = (guint32 *)(void *)code;
mips_nop (code);
break;
+ case OP_MIPS_COND_EXC_LT_UN:
+ mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
+ throw = (guint32 *)(void *)code;
+ mips_bne (code, mips_at, mips_zero, 0);
+ mips_nop (code);
+ break;
+
default:
/* Not yet implemented */
g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
/* floating point opcodes */
case OP_R8CONST:
+#if 0
if (((guint32)ins->inst_p0) & (1 << 15))
mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
else
mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
+#else
+ mips_load_const (code, mips_at, ins->inst_p0);
+ mips_lwc1 (code, ins->dreg, mips_at, 4);
+ mips_lwc1 (code, ins->dreg+1, mips_at, 0);
+#endif
break;
case OP_R4CONST:
if (((guint32)ins->inst_p0) & (1 << 15))
else
mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
+#if PROMOTE_R4_TO_R8
mips_cvtds (code, ins->dreg, ins->dreg);
+#endif
break;
case OP_STORER8_MEMBASE_REG:
if (mips_is_imm16 (ins->inst_offset)) {
-#if 1
- mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+ mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
#endif
} else {
mips_load_const (code, mips_at, ins->inst_offset);
break;
case OP_LOADR8_MEMBASE:
if (mips_is_imm16 (ins->inst_offset)) {
-#if 1
- mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+ mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
#endif
} else {
mips_load_const (code, mips_at, ins->inst_offset);
}
break;
case OP_STORER4_MEMBASE_REG:
- /* XXX Need to convert ins->sreg1 to single-precision first */
+ g_assert (mips_is_imm16 (ins->inst_offset));
+#if PROMOTE_R4_TO_R8
+ /* Need to convert ins->sreg1 to single-precision first */
mips_cvtsd (code, mips_ftemp, ins->sreg1);
- if (mips_is_imm16 (ins->inst_offset)) {
- mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
- } else {
- mips_load_const (code, mips_at, ins->inst_offset);
- mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
- mips_swc1 (code, mips_ftemp, mips_at, 0);
- }
+ mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
+#else
+ mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+#endif
break;
case OP_MIPS_LWC1:
- if (mips_is_imm16 (ins->inst_offset)) {
- mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
- } else {
- mips_load_const (code, mips_at, ins->inst_offset);
- mips_addu (code, mips_at, mips_at, ins->inst_basereg);
- mips_lwc1 (code, ins->dreg, mips_at, 0);
- }
+ g_assert (mips_is_imm16 (ins->inst_offset));
+ mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
break;
case OP_LOADR4_MEMBASE:
- if (mips_is_imm16 (ins->inst_offset)) {
- mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
- } else {
- mips_load_const (code, mips_at, ins->inst_offset);
- mips_addu (code, mips_at, mips_at, ins->inst_basereg);
- mips_lwc1 (code, ins->dreg, mips_at, 0);
- }
+ g_assert (mips_is_imm16 (ins->inst_offset));
+ mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+#if PROMOTE_R4_TO_R8
/* Convert to double precision in place */
mips_cvtds (code, ins->dreg, ins->dreg);
+#endif
+ break;
+ case OP_LOADR4_MEMINDEX:
+ mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
+ mips_lwc1 (code, ins->dreg, mips_at, 0);
+ break;
+ case OP_LOADR8_MEMINDEX:
+ mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
+#if _MIPS_SIM == _ABIO32
+ mips_lwc1 (code, ins->dreg, mips_at, 0);
+ mips_lwc1 (code, ins->dreg+1, mips_at, 4);
+#elif _MIPS_SIM == _ABIN32
+ mips_ldc1 (code, ins->dreg, mips_at, 0);
+#endif
+ break;
+ case OP_STORER4_MEMINDEX:
+ mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
+#if PROMOTE_R4_TO_R8
+ /* Need to convert ins->sreg1 to single-precision first */
+ mips_cvtsd (code, mips_ftemp, ins->sreg1);
+ mips_swc1 (code, mips_ftemp, mips_at, 0);
+#else
+ mips_swc1 (code, ins->sreg1, mips_at, 0);
+#endif
+ break;
+ case OP_STORER8_MEMINDEX:
+ mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
+#if _MIPS_SIM == _ABIO32
+ mips_swc1 (code, ins->sreg1, mips_at, 0);
+ mips_swc1 (code, ins->sreg1+1, mips_at, 4);
+#elif _MIPS_SIM == _ABIN32
+ mips_sdc1 (code, ins->sreg1, mips_at, 0);
+#endif
break;
case OP_ICONV_TO_R_UN: {
static const guint64 adjust_val = 0x41F0000000000000ULL;
case OP_FCONV_TO_U:
code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
break;
- case OP_FCONV_TO_I8:
- case OP_FCONV_TO_U8:
- g_assert_not_reached ();
- /* Implemented as helper calls */
- break;
- case OP_LCONV_TO_R_UN:
- g_assert_not_reached ();
- /* Implemented as helper calls */
- break;
- case OP_LCONV_TO_OVF_I:
- g_assert_not_reached ();
- /* split up by brg file */
- break;
case OP_SQRT:
mips_fsqrtd (code, ins->dreg, ins->sreg1);
break;
case OP_FNEG:
mips_fnegd (code, ins->dreg, ins->sreg1);
break;
- case OP_FREM:
- /* emulated */
- g_assert_not_reached ();
- break;
- case OP_FCOMPARE:
- g_assert_not_reached();
- break;
case OP_FCEQ:
mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_fbtrue (code, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_FCLT:
mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_fbtrue (code, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_FCLT_UN:
/* Less than, or Unordered */
mips_addiu (code, ins->dreg, mips_zero, 1);
mips_fbtrue (code, 2);
mips_nop (code);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_FCGT:
mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
mips_fbtrue (code, 2);
mips_nop (code);
mips_addiu (code, ins->dreg, mips_zero, 1);
case OP_FCGT_UN:
/* Greater than, or Unordered */
mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
- mips_move (code, ins->dreg, mips_zero);
+ MIPS_MOVE (code, ins->dreg, mips_zero);
mips_fbtrue (code, 2);
mips_nop (code);
mips_addiu (code, ins->dreg, mips_zero, 1);
case OP_MIPS_FBEQ:
mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbtrue (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBNE:
mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbfalse (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBLT:
mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbtrue (code, 0);
mips_nop (code);
break;
- case OP_FBLT_UN:
+ case OP_MIPS_FBLT_UN:
mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbtrue (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBGT:
mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbfalse (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBGT_UN:
mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbfalse (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBGE:
mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbfalse (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBGE_UN:
mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbfalse (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBLE:
mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbtrue (code, 0);
mips_nop (code);
break;
case OP_MIPS_FBLE_UN:
mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
mips_nop (code);
- if (ins->flags & MONO_INST_BRLABEL)
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- else
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
mips_fbtrue (code, 0);
mips_nop (code);
break;
case OP_CKFINITE: {
- g_assert_not_reached();
-#if 0
- ppc_stfd (code, ins->sreg1, -8, ppc_sp);
- ppc_lwz (code, ppc_r11, -8, ppc_sp);
- ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
- ppc_addis (code, ppc_r11, ppc_r11, -32752);
- ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
- EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
-#endif
+ guint32 *branch_patch;
+
+ mips_mfc1 (code, mips_at, ins->sreg1+1);
+ mips_srl (code, mips_at, mips_at, 16+4);
+ mips_andi (code, mips_at, mips_at, 2047);
+ mips_addiu (code, mips_at, mips_at, -2047);
+
+ branch_patch = (guint32 *)(void *)code;
+ mips_bne (code, mips_at, mips_zero, 0);
+ mips_nop (code);
+
+ EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
+ mips_patch (branch_patch, (guint32)code);
+ mips_fmovd (code, ins->dreg, ins->sreg1);
break;
}
case OP_JUMP_TABLE:
- mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+ mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
mips_load (code, ins->dreg, 0x0f0f0f0f);
break;
}
void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
{
MonoJumpInfo *patch_info;
for (patch_info = ji; patch_info; patch_info = patch_info->next) {
unsigned char *ip = patch_info->ip.i + code;
- const unsigned char *target;
-
- target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+ const unsigned char *target = NULL;
switch (patch_info->type) {
case MONO_PATCH_INFO_IP:
case MONO_PATCH_INFO_R4:
case MONO_PATCH_INFO_R8:
/* from OP_AOTCONST : lui + addiu */
+ target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
continue;
#if 0
/* everything is dealt with at epilog output time */
continue;
default:
+ target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+ mips_patch ((guint32 *)(void *)ip, (guint32)target);
break;
}
- mips_patch ((guint32 *)(void *)ip, (guint32)target);
}
}
+#if 0
static
void
mono_trace_lmf_prolog (MonoLMF *new_lmf)
mono_trace_lmf_epilog (MonoLMF *old_lmf)
{
}
+#endif
/*
* Allow tracing to work with this interface (with an optional argument)
mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
{
guchar *code = p;
- int fp_stack_offset = 0;
+ int offset = cfg->arch.tracing_offset;
mips_nop (code);
mips_nop (code);
mips_nop (code);
- mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
- mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
- mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
- mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
-#if 0
-#if 0
- fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
- mips_addiu (code, mips_sp, mips_sp, -64);
- mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
- mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
- mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
- mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
-#else
- mips_fmovs (code, mips_f22, mips_f12);
- mips_fmovs (code, mips_f23, mips_f13);
- mips_fmovs (code, mips_f24, mips_f14);
- mips_fmovs (code, mips_f25, mips_f15);
-#endif
+ /* For N32, need to know for each stack slot if it's an integer
+ * or float argument, and save/restore the appropriate register
+ */
+ MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
+#if _MIPS_SIM == _ABIN32
+ MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
+ MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
#endif
- mips_load_const (code, mips_a0, cfg->method);
- mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
- mips_load_const (code, mips_t9, func);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
- mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
- mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
- mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
- mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
-#if 0
-#if 0
- mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
- mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
- mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
- mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
- mips_addiu (code, mips_sp, mips_sp, 64);
-#else
- mips_fmovs (code, mips_f12, mips_f22);
- mips_fmovs (code, mips_f13, mips_f23);
- mips_fmovs (code, mips_f14, mips_f24);
- mips_fmovs (code, mips_f15, mips_f25);
-#endif
+ mips_load_const (code, mips_a0, cfg->method);
+ mips_addiu (code, mips_a1, mips_sp, offset);
+ mips_call (code, mips_t9, func);
+
+ MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
+#if _MIPS_SIM == _ABIN32
+ MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
+ MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
#endif
+
mips_nop (code);
mips_nop (code);
mips_nop (code);
return;
/* adjust cfg->stack_offset for account for down-spilling */
- cfg->stack_offset += 4;
+ cfg->stack_offset += SIZEOF_REGISTER;
/* re-align cfg->stack_offset if needed (due to var spilling) */
cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
}
threshold = cfg->arch.local_alloc_offset;
- ra_offset = cfg->stack_offset - 4;
+ ra_offset = cfg->stack_offset - sizeof(gpointer);
if (cfg->verbose_level > 2) {
g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
}
g_print ("BASIC BLOCK %d:\n", bb->block_num);
}
MONO_BB_FOR_EACH_INS (bb, ins) {
+ int adj_c0 = 0;
+ int adj_imm = 0;
+
if (cfg->verbose_level > 2) {
mono_print_ins_index (ins_cnt, ins);
}
- if ((MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp)) || (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))) {
+ if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
+ adj_c0 = 1;
+ if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
+ adj_c0 = 1;
+ /* The following two catch FP spills */
+ if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
+ adj_c0 = 1;
+ if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
+ adj_c0 = 1;
+ if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
+ adj_imm = 1;
+ if (adj_c0) {
if (ins->inst_c0 >= threshold) {
ins->inst_c0 += delta;
if (cfg->verbose_level > 2) {
}
g_assert (ins->inst_c0 != ra_offset);
}
+ if (adj_imm) {
+ if (ins->inst_imm >= threshold) {
+ ins->inst_imm += delta;
+ if (cfg->verbose_level > 2) {
+ g_print ("adj");
+ mono_print_ins_index (ins_cnt, ins);
+ }
+ }
+ g_assert (ins->inst_c0 != ra_offset);
+ }
+
++ins_cnt;
}
}
MonoMethodSignature *sig;
MonoInst *inst;
int alloc_size, pos, i;
+ int alloc2_size = 0;
guint8 *code;
CallInfo *cinfo;
int tracing = 0;
cfg->code_size = 768 + sig->param_count * 20;
code = cfg->native_code = g_malloc (cfg->code_size);
+ if (tracing) {
+#if _MIPS_SIM == _ABIO32
+ cfg->arch.tracing_offset = cfg->stack_offset;
+#elif _MIPS_SIM == _ABIN32
+ /* no stack slots by default for argument regs, reserve a special block */
+ cfg->arch.tracing_offset = cfg->stack_offset;
+ cfg->stack_offset += 8 * SIZEOF_REGISTER;
+#endif
+ }
+
/* adjust stackframe assignments for spillvars if needed */
mips_adjust_stackframe (cfg);
fregs_to_save |= (fregs_to_save << 1);
#endif
#endif
+ /* If the stack size is too big, save 1024 bytes to start with
+ * so the prologue can use imm16(reg) addressing, then allocate
+ * the rest of the frame.
+ */
+ if (alloc_size > ((1 << 15) - 1024)) {
+ alloc2_size = alloc_size - 1024;
+ alloc_size = 1024;
+ }
if (alloc_size) {
- if (mips_is_imm16 (-alloc_size)) {
- mips_addiu (code, mips_sp, mips_sp, -alloc_size);
- } else {
- mips_load_const (code, mips_at, -alloc_size);
- mips_addu (code, mips_sp, mips_sp, mips_at);
- }
+ g_assert (mips_is_imm16 (-alloc_size));
+ mips_addiu (code, mips_sp, mips_sp, -alloc_size);
}
- if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
- mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
+ if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
+ int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
+ if (mips_is_imm16(offset))
+ mips_sw (code, mips_ra, mips_sp, offset);
+ else {
+ g_assert_not_reached ();
+ }
+ }
/* XXX - optimize this later to not save all regs if LMF constructed */
+ pos = cfg->arch.iregs_offset - alloc2_size;
if (iregs_to_save) {
/* save used registers in own stack frame (at pos) */
- pos = cfg->arch.iregs_offset;
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_save & (1 << i)) {
- g_assert (pos < cfg->stack_usage - 4);
- mips_sw (code, i, mips_sp, pos);
- pos += sizeof (gulong);
+ g_assert (pos < cfg->stack_usage - sizeof(gpointer));
+ g_assert (mips_is_imm16(pos));
+ MIPS_SW (code, i, mips_sp, pos);
+ pos += SIZEOF_REGISTER;
}
}
}
#if SAVE_LMF
if (method->save_lmf) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
- mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
+ g_assert (mips_is_imm16(offset));
+ MIPS_SW (code, i, mips_sp, offset);
}
}
#endif
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
if (fregs_to_save & (1 << i)) {
g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
+ g_assert (mips_is_imm16(pos));
mips_swc1 (code, i, mips_sp, pos);
pos += sizeof (gulong);
}
#if SAVE_LMF
if (method->save_lmf) {
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
- mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
+ g_assert (mips_is_imm16(offset));
+ mips_swc1 (code, i, mips_sp, offset);
}
}
#endif
#endif
if (cfg->frame_reg != mips_sp) {
- mips_move (code, cfg->frame_reg, mips_sp);
+ MIPS_MOVE (code, cfg->frame_reg, mips_sp);
#if SAVE_LMF
- if (method->save_lmf)
- mips_sw (code, cfg->frame_reg, mips_sp,
- lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
+ if (method->save_lmf) {
+ int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
+ g_assert (mips_is_imm16(offset));
+ MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
+ }
#endif
}
/* Do instrumentation before assigning regvars to registers. Because they may be assigned
* to the t* registers, which would be clobbered by the instrumentation calls.
*/
- if (tracing)
+ if (tracing) {
code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
+ }
/* load arguments allocated to register from the stack */
ArgInfo *ainfo = &cinfo->ret;
inst = cfg->vret_addr;
if (inst->opcode == OP_REGVAR)
- mips_move (code, inst->dreg, ainfo->reg);
+ MIPS_MOVE (code, inst->dreg, ainfo->reg);
else if (mips_is_imm16 (inst->inst_offset)) {
mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
} else {
if (inst->opcode == OP_REGVAR) {
/* Argument ends up in a register */
if (ainfo->regtype == RegTypeGeneral)
- mips_move (code, inst->dreg, ainfo->reg);
+ MIPS_MOVE (code, inst->dreg, ainfo->reg);
else if (ainfo->regtype == RegTypeFP) {
g_assert_not_reached();
#if 0
#endif
}
else if (ainfo->regtype == RegTypeBase) {
- mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
+ int offset = cfg->stack_usage + ainfo->offset;
+ g_assert (mips_is_imm16(offset));
+ mips_lw (code, inst->dreg, mips_sp, offset);
} else
g_assert_not_reached ();
mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
break;
case 8:
+#if (SIZEOF_REGISTER == 4)
mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
+#elif (SIZEOF_REGISTER == 8)
+ mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+#endif
break;
default:
g_assert_not_reached ();
}
} else if (ainfo->regtype == RegTypeFP) {
g_assert (mips_is_imm16 (inst->inst_offset));
+ g_assert (mips_is_imm16 (inst->inst_offset+4));
if (ainfo->size == 8) {
-#if 1
- mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
-#else
+#if _MIPS_SIM == _ABIO32
mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
+#elif _MIPS_SIM == _ABIN32
+ mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
#endif
}
else if (ainfo->size == 4)
g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
/* Push the argument registers into their stack slots */
for (i = 0; i < ainfo->size; ++i) {
- mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
- doffset += sizeof (gpointer);
+ g_assert (mips_is_imm16(doffset));
+ MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
+ doffset += SIZEOF_REGISTER;
}
} else if (ainfo->regtype == RegTypeStructByAddr) {
g_assert (mips_is_imm16 (inst->inst_offset));
if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
mips_load_const (code, mips_a0, cfg->domain);
- mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
}
#if SAVE_LMF
#if 0
emit_tls_access (code, mips_temp, lmf_pthread_key);
#endif
- if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
- mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
+ if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
+ int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
+ g_assert (mips_is_imm16(offset));
+ mips_addiu (code, mips_a0, mips_temp, offset);
+ }
} else {
-#if 0
- mips_addiu (code, mips_a0, mips_sp, lmf_offset);
- mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
-#endif
/* This can/will clobber the a0-a3 registers */
- mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
}
/* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
/* new_lmf->previous_lmf = *lmf_addr */
mips_lw (code, mips_at, mips_v0, 0);
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
/* *(lmf_addr) = sp + lmf_offset */
+ g_assert (mips_is_imm16(lmf_offset));
mips_addiu (code, mips_at, mips_sp, lmf_offset);
mips_sw (code, mips_at, mips_v0, 0);
/* save method info */
mips_load_const (code, mips_at, method);
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
- mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
+ MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
/* save the current IP */
mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
}
#endif
+ if (alloc2_size) {
+ if (mips_is_imm16 (-alloc2_size)) {
+ mips_addu (code, mips_sp, mips_sp, -alloc2_size);
+ }
+ else {
+ mips_load_const (code, mips_at, -alloc2_size);
+ mips_addu (code, mips_sp, mips_sp, mips_at);
+ }
+ if (cfg->frame_reg != mips_sp)
+ MIPS_MOVE (code, cfg->frame_reg, mips_sp);
+ alloc_size += alloc2_size;
+ }
cfg->code_len = code - cfg->native_code;
g_assert (cfg->code_len < cfg->code_size);
};
void*
-mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
+mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
{
guchar *code = p;
int save_mode = SAVE_NONE;
else
save_mode = SAVE_NONE;
break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- save_mode = SAVE_TWO;
- break;
case MONO_TYPE_R4:
case MONO_TYPE_R8:
save_mode = SAVE_FP;
case MONO_TYPE_VALUETYPE:
save_mode = SAVE_STRUCT;
break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+#if SIZEOF_REGISTER == 4
+ save_mode = SAVE_TWO;
+#elif SIZEOF_REGISTER == 8
+ save_mode = SAVE_ONE;
+#endif
+ break;
default:
save_mode = SAVE_ONE;
break;
}
mips_addiu (code, mips_sp, mips_sp, -32);
+ g_assert (mips_is_imm16(save_offset));
switch (save_mode) {
case SAVE_TWO:
mips_sw (code, mips_v0, mips_sp, save_offset);
- mips_sw (code, mips_v1, mips_sp, save_offset + 4);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
+ mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
if (enable_arguments) {
- mips_move (code, mips_a1, mips_v0);
- mips_move (code, mips_a2, mips_v1);
+ MIPS_MOVE (code, mips_a1, mips_v0);
+ MIPS_MOVE (code, mips_a2, mips_v1);
}
break;
case SAVE_ONE:
- mips_sw (code, mips_v0, mips_sp, save_offset);
+ MIPS_SW (code, mips_v0, mips_sp, save_offset);
if (enable_arguments) {
- mips_move (code, mips_a1, mips_v0);
+ MIPS_MOVE (code, mips_a1, mips_v0);
}
break;
case SAVE_FP:
mips_sdc1 (code, mips_f0, mips_sp, save_offset);
mips_ldc1 (code, mips_f12, mips_sp, save_offset);
mips_lw (code, mips_a0, mips_sp, save_offset);
- mips_lw (code, mips_a1, mips_sp, save_offset+4);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
+ mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
break;
case SAVE_STRUCT:
case SAVE_NONE:
break;
}
mips_load_const (code, mips_a0, cfg->method);
- mips_load_const (code, mips_t9, func);
- mips_jalr (code, mips_t9, mips_ra);
- mips_nop (code);
+ mips_call (code, mips_t9, func);
switch (save_mode) {
case SAVE_TWO:
mips_lw (code, mips_v0, mips_sp, save_offset);
- mips_lw (code, mips_v1, mips_sp, save_offset + 4);
+ g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
+ mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
break;
case SAVE_ONE:
- mips_lw (code, mips_v0, mips_sp, save_offset);
+ MIPS_LW (code, mips_v0, mips_sp, save_offset);
break;
case SAVE_FP:
mips_ldc1 (code, mips_f0, mips_sp, save_offset);
mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
{
MonoMethod *method = cfg->method;
- int pos, i;
+ int pos = 0, i;
int max_epilog_size = 16 + 20*4;
+ int alloc2_size = 0;
guint32 iregs_to_restore;
#if SAVE_FP_REGS
guint32 fregs_to_restore;
if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
}
- pos = cfg->arch.iregs_offset;
if (cfg->frame_reg != mips_sp) {
- mips_move (code, mips_sp, cfg->frame_reg);
+ MIPS_MOVE (code, mips_sp, cfg->frame_reg);
+ }
+ /* If the stack frame is really large, deconstruct it in two steps */
+ if (cfg->stack_usage > ((1 << 15) - 1024)) {
+ alloc2_size = cfg->stack_usage - 1024;
+ /* partially deconstruct the stack */
+ mips_load_const (code, mips_at, alloc2_size);
+ mips_addu (code, mips_sp, mips_sp, mips_at);
}
+ pos = cfg->arch.iregs_offset - alloc2_size;
#if SAVE_ALL_REGS
iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
#else
if (iregs_to_restore) {
for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
if (iregs_to_restore & (1 << i)) {
- mips_lw (code, i, mips_sp, pos);
- pos += sizeof (gulong);
+ g_assert (mips_is_imm16(pos));
+ MIPS_LW (code, i, mips_sp, pos);
+ pos += SIZEOF_REGISTER;
}
}
}
for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
if (fregs_to_restore & (1 << i)) {
g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
+ g_assert (mips_is_imm16(pos));
mips_lwc1 (code, i, mips_sp, pos);
- pos += sizeof (gulong);
+ pos += FREG_SIZE
}
}
}
int lmf_offset = cfg->arch.lmf_offset;
/* t0 = current_lmf->previous_lmf */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
/* t1 = lmf_addr */
+ g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
/* (*lmf_addr) = previous_lmf */
mips_sw (code, mips_temp, mips_t1, 0);
/* Restore the fp */
mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
#endif
- /* Correct the stack pointer */
- if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
- mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
- mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
+ /* Restore ra */
+ if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
+ g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
+ mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
+ }
+ /* Restore the stack pointer */
+ g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
+ mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
/* Caller will emit either return or tail-call sequence */
}
/* remove once throw_exception_by_name is eliminated */
+#if 0
static int
exception_id_by_name (const char *name)
{
return MONO_EXC_NULL_REF;
if (strcmp (name, "ArrayTypeMismatchException") == 0)
return MONO_EXC_ARRAY_TYPE_MISMATCH;
+ if (strcmp (name, "ArgumentException") == 0)
+ return MONO_EXC_ARGUMENT;
g_error ("Unknown intrinsic exception %s\n", name);
return 0;
}
+#endif
void
mono_arch_emit_exceptions (MonoCompile *cfg)
return ins;
}
-MonoInst*
-mono_arch_get_thread_intrinsic (MonoCompile* cfg)
-{
- MonoInst* ins;
-
- setup_tls_access ();
- if (monothread_key == -1)
- return NULL;
-
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->inst_offset = monothread_key;
- return ins;
-}
-
gpointer
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
#ifdef MONO_ARCH_HAVE_IMT
-#define CMP_SIZE 12
-#define BR_SIZE 4
-#define JUMP_IMM_SIZE 12
-#define JUMP_IMM32_SIZE 16
#define ENABLE_WRONG_METHOD_CHECK 0
+#define MIPS_LOAD_SEQUENCE_LENGTH 8
+#define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
+#define BR_SIZE 8
+#define LOADSTORE_SIZE 4
+#define JUMP_IMM_SIZE 16
+#define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
+#define LOAD_CONST_SIZE 8
+#define JUMP_JR_SIZE 8
+
/*
* LOCKING: called with the domain lock held
*/
mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
gpointer fail_tramp)
{
- NOT_IMPLEMENTED;
-#if 0
int i;
int size = 0;
- guint8 *code, *start;
+ guint8 *code, *start, *patch;
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
+
+ item->chunk_size += LOAD_CONST_SIZE;
if (item->is_equals) {
if (item->check_target_idx) {
- if (!item->compare_done)
- item->chunk_size += CMP_SIZE;
- if (fail_tramp)
- item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
- else
- item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
+ item->chunk_size += BR_SIZE + LOAD_CONST_SIZE + JUMP_JR_SIZE;
} else {
if (fail_tramp) {
- item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
+ item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE * 2;
+ if (!item->has_target_code)
+ item->chunk_size += LOADSTORE_SIZE;
} else {
- item->chunk_size += JUMP_IMM_SIZE;
+ item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
#if ENABLE_WRONG_METHOD_CHECK
item->chunk_size += CMP_SIZE + BR_SIZE + 4;
#endif
}
}
} else {
- item->chunk_size += CMP_SIZE + BR_SIZE;
+ item->chunk_size += BR_SIZE;
imt_entries [item->check_target_idx]->compare_done = TRUE;
}
size += item->chunk_size;
}
+ /* the initial load of the vtable address */
+ size += MIPS_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
if (fail_tramp) {
code = mono_method_alloc_generic_virtual_thunk (domain, size);
} else {
- /* the initial load of the vtable address */
- size += 8;
- code = mono_code_manager_reserve (domain->code_mp, size);
+ code = mono_domain_code_reserve (domain, size);
}
start = code;
- if (!fail_tramp)
- ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
+
+#if 0
+ /*
+ * We need to save and restore r11 because it might be
+ * used by the caller as the vtable register, so
+ * clobbering it will trip up the magic trampoline.
+ *
+ * FIXME: Get rid of this by making sure that r11 is
+ * not used as the vtable register in interface calls.
+ */
+ ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
+ ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
+#endif
+ /* t7 points to the vtable */
+ mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
+
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
+
item->code_target = code;
if (item->is_equals) {
if (item->check_target_idx) {
- if (!item->compare_done) {
- ppc_load (code, ppc_r0, (guint32)item->key);
- ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
- }
+ mips_load_const (code, mips_temp, (gsize)item->key);
item->jmp_code = code;
- ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
- if (fail_tramp)
- ppc_load (code, ppc_r0, item->value.target_code);
- else
- ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
- ppc_mtctr (code, ppc_r0);
- ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+ mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
+ mips_nop (code);
+ if (item->has_target_code) {
+ mips_load_const (code, mips_t9,
+ item->value.target_code);
+ }
+ else {
+ mips_lw (code, mips_t9, mips_t7,
+ (sizeof (gpointer) * item->value.vtable_slot));
+ }
+ mips_jr (code, mips_t9);
+ mips_nop (code);
} else {
if (fail_tramp) {
- ppc_load (code, ppc_r0, (guint32)item->key);
- ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
- item->jmp_code = code;
- ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
- ppc_load (code, ppc_r0, item->value.target_code);
- ppc_mtctr (code, ppc_r0);
- ppc_bcctr (code, PPC_BR_ALWAYS, 0);
- ppc_patch (item->jmp_code, code);
- ppc_load (code, ppc_r0, fail_tramp);
- ppc_mtctr (code, ppc_r0);
- ppc_bcctr (code, PPC_BR_ALWAYS, 0);
- item->jmp_code = NULL;
+ mips_load_const (code, mips_temp, (gsize)item->key);
+ patch = code;
+ mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
+ mips_nop (code);
+ if (item->has_target_code) {
+ mips_load_const (code, mips_t9,
+ item->value.target_code);
+ } else {
+ g_assert (vtable);
+ mips_load_const (code, mips_at,
+ & (vtable->vtable [item->value.vtable_slot]));
+ mips_lw (code, mips_t9, mips_at, 0);
+ }
+ mips_jr (code, mips_t9);
+ mips_nop (code);
+ mips_patch ((guint32 *)(void *)patch, (guint32)code);
+ mips_load_const (code, mips_at, fail_tramp);
+ mips_lw (code, mips_t9, mips_at, 0);
+ mips_jr (code, mips_t9);
+ mips_nop (code);
} else {
/* enable the commented code to assert on wrong method */
#if ENABLE_WRONG_METHOD_CHECK
ppc_load (code, ppc_r0, (guint32)item->key);
- ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
- item->jmp_code = code;
+ ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
+ patch = code;
ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
#endif
- ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
- ppc_mtctr (code, ppc_r0);
- ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+ mips_lw (code, mips_t9, mips_t7,
+ (sizeof (gpointer) * item->value.vtable_slot));
+ mips_jr (code, mips_t9);
+ mips_nop (code);
+
#if ENABLE_WRONG_METHOD_CHECK
- ppc_patch (item->jmp_code, code);
+ ppc_patch (patch, code);
ppc_break (code);
- item->jmp_code = NULL;
#endif
}
}
} else {
- ppc_load (code, ppc_r0, (guint32)item->key);
- ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
+ mips_load_const (code, mips_temp, (gulong)item->key);
+ mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
+
item->jmp_code = code;
- ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
+ mips_beq (code, mips_temp, mips_zero, 0);
+ mips_nop (code);
}
}
/* patch the branches to get to the target items */
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
- if (item->jmp_code) {
- if (item->check_target_idx) {
- ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
- }
+ if (item->jmp_code && item->check_target_idx) {
+ mips_patch ((guint32 *)item->jmp_code,
+ (guint32)imt_entries [item->check_target_idx]->code_target);
}
}
g_assert (code - start <= size);
mono_arch_flush_icache (start, size);
return start;
-#endif
}
MonoMethod*
-mono_arch_find_imt_method (gpointer *regs, guint8 *code)
+mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
{
return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
}
-
-MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
-{
- return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
-}
#endif
MonoVTable*
-mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
+mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
{
NOT_IMPLEMENTED;
return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];