#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
+#include <mono/arch/mips/mips-codegen.h>
+
#include "mini-mips.h"
-#include "inssel.h"
#include "cpu-mips.h"
#include "trace.h"
+#include "ir-emit.h"
#define SAVE_FP_REGS 0
#define SAVE_ALL_REGS 0
#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 */
+
enum {
TLS_MODE_DETECT,
TLS_MODE_FAILED,
TLS_MODE_NPTL
};
+/* This mutex protects architecture specific caches */
+#define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
+#define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
+static CRITICAL_SECTION mini_arch_mutex;
+
int mono_exc_esp_offset = 0;
static int tls_mode = TLS_MODE_DETECT;
static int lmf_pthread_key = -1;
#define emit_linuxthreads_tls(code,dreg,key) do {\
int off1, off2; \
off1 = offsets_from_pthread_key ((key), &off2); \
+ g_assert_not_reached (); \
ppc_lwz ((code), (dreg), off1, ppc_r2); \
ppc_lwz ((code), (dreg), off2, (dreg)); \
} while (0);
} \
} while (0)
+#define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
+ MonoInst *inst; \
+ MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
+ inst->type = STACK_R8; \
+ inst->dreg = (dr); \
+ inst->inst_p0 = (void*)(addr); \
+ mono_bblock_add_inst (cfg->cbb, inst); \
+ } while (0)
+
+#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 s2 = _s2; \
+ ins->opcode = (op); \
+ ins->sreg1 = (s1); \
+ ins->sreg2 = (s2); \
+ } while (0);
+
+#define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
+ int s1 = _s1; \
+ ins->opcode = (op); \
+ ins->sreg1 = (s1); \
+ ins->inst_imm = (_imm); \
+ } while (0);
+
+
typedef struct InstList InstList;
struct InstList {
MonoInst *data;
};
-#define ALWAYS_ON_STACK(s) s
-#define FP_ALSO_IN_REG(s) s
-#define ALIGN_DOUBLES
-
enum {
RegTypeGeneral,
RegTypeBase,
int nargs;
int gr;
int fr;
- int gr_passed;
- int fr_passed;
+ gboolean gr_passed;
gboolean on_stack;
int stack_size;
guint32 stack_usage;
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)
cacheflush (code, size, BCACHE);
}
-#ifndef CUSTOM_STACK_WALK
void
mono_arch_flush_register_windows (void)
{
}
-#endif
+
+gboolean
+mono_arch_is_inst_imm (gint64 imm)
+{
+ return TRUE;
+}
static guint8 *
mips_emit_exc_by_name(guint8 *code, const char *name)
return code;
}
-static guint8 *
+
+guint8 *
+mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
+{
+ if (mips_is_imm16 (v))
+ mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
+ else {
+#ifdef 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)
{
+#if LONG_BRANCH
int br_offset = 5;
+#endif
g_assert (ins);
#if LONG_BRANCH
}
}
+#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";
arg_info [0].size = frame_size;
for (k = 0; k < param_count; k++) {
-
- if (csig->pinvoke)
- size = mono_type_native_stack_size (csig->params [k], &align);
- else
- size = mono_type_stack_size (csig->params [k], &align);
+ size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
/* ignore alignment for now */
align = 1;
return frame_size;
}
+
+gpointer
+mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
+{
+ /* FIXME: handle returning a struct */
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ return (gpointer)regs [mips_a1];
+ return (gpointer)regs [mips_a0];
+}
+
/*
* Initialize the cpu to execute managed code.
*/
void
mono_arch_init (void)
{
+ InitializeCriticalSection (&mini_arch_mutex);
}
/*
void
mono_arch_cleanup (void)
{
+ DeleteCriticalSection (&mini_arch_mutex);
}
/*
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:
regs = g_list_prepend (regs, (gpointer)mips_s2);
regs = g_list_prepend (regs, (gpointer)mips_s3);
regs = g_list_prepend (regs, (gpointer)mips_s4);
- regs = g_list_prepend (regs, (gpointer)mips_s5);
+ //regs = g_list_prepend (regs, (gpointer)mips_s5);
regs = g_list_prepend (regs, (gpointer)mips_s6);
regs = g_list_prepend (regs, (gpointer)mips_s7);
}
static void
-args_onto_stack (CallInfo *info, gboolean force)
+args_onto_stack (CallInfo *info)
{
- if (!info->on_stack) {
- if ((info->gr > MIPS_LAST_ARG_REG) || (info->fr > (MIPS_LAST_FPARG_REG+1))) {
- force = TRUE;
- }
- if (force) {
- info->on_stack = TRUE;
- 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
*/
static void
add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
/* First, see if we need to drop onto the stack */
- args_onto_stack (info, FALSE);
+ if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
/* Now, place the argument */
- ainfo->offset = info->stack_size;
- info->stack_size += 4;
if (info->on_stack) {
ainfo->regtype = RegTypeBase;
ainfo->reg = mips_sp; /* in the caller */
+ ainfo->offset = info->stack_size;
}
else {
+ ainfo->regtype = RegTypeGeneral;
ainfo->reg = info->gr;
info->gr += 1;
- info->gr_passed += 1;
- /* FP and GP slots do not overlap */
- info->fr += 1;
+ info->gr_passed = TRUE;
}
+ info->stack_size += 4;
}
static void
add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
/* First, see if we need to drop onto the stack */
- args_onto_stack (info, FALSE);
+ if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
/* Now, place the argument */
- if (info->stack_size & 0x7) {
- ArgInfo dummy;
-
- /* foo (int, long) -- need to align 2nd arg */
- add_int32_arg (info, &dummy);
- args_onto_stack (info, FALSE);
- }
- ainfo->offset = info->stack_size;
- info->stack_size += 8;
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;
}
else {
+ // info->gr must be a0 or a2
+ info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
+ g_assert(info->gr <= MIPS_LAST_ARG_REG);
+
+ ainfo->regtype = RegTypeGeneral;
ainfo->reg = info->gr;
info->gr += 2;
- info->gr_passed += 2;
- /* FP and GP slots do not overlap */
- info->fr += 2;
+ info->gr_passed = TRUE;
}
+ info->stack_size += 8;
}
static void
add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
/* First, see if we need to drop onto the stack */
- args_onto_stack (info, FALSE);
+ if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
/* Now, place the argument */
- ainfo->offset = info->stack_size;
if (info->on_stack) {
ainfo->regtype = RegTypeBase;
ainfo->reg = mips_sp; /* in the caller */
- info->stack_size += 8;
+ ainfo->offset = info->stack_size;
}
else {
/* Only use FP regs for args if no int args passed yet */
- if (!info->gr_passed) {
+ if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
ainfo->regtype = RegTypeFP;
ainfo->reg = info->fr;
- info->stack_size += 8;
/* Even though it's a single-precision float, it takes up two FP regs */
info->fr += 2;
- info->fr_passed += 1;
/* FP and GP slots do not overlap */
- info->gr += 2;
+ info->gr += 1;
}
else {
/* Passing single-precision float arg in a GP register
*/
ainfo->regtype = RegTypeGeneral;
ainfo->reg = info->gr;
- info->stack_size += 4;
- /* Even though it's a single-precision float, it takes up two FP regs */
- info->fr += 1;
- info->fr_passed += 1;
- /* FP and GP slots do not overlap */
info->gr += 1;
+ info->gr_passed = TRUE;
}
}
+ info->stack_size += 4;
}
static void
add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
/* First, see if we need to drop onto the stack */
- args_onto_stack (info, FALSE);
+ if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
+ args_onto_stack (info);
/* Now, place the argument */
-#ifdef ALIGN_DOUBLES
- // info->stack_size += (info->stack_size % 8);
-#endif
- ainfo->offset = info->stack_size;
- info->stack_size += 8;
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;
}
else {
/* Only use FP regs for args if no int args passed yet */
- if (!info->gr_passed) {
+ if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
ainfo->regtype = RegTypeFP;
ainfo->reg = info->fr;
+ info->fr += 2;
+ /* FP and GP slots do not overlap */
+ info->gr += 2;
}
else {
+ // info->gr must be a0 or a2
+ info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
+ g_assert(info->gr <= MIPS_LAST_ARG_REG);
+
ainfo->regtype = RegTypeGeneral;
ainfo->reg = info->gr;
+ info->gr += 2;
+ info->gr_passed = TRUE;
}
- info->fr += 2;
- info->fr_passed += 2;
+ }
+ 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 += 2;
+ 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)
if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
/* Prevent implicit arguments and sig_cookie from
being passed in registers */
- args_onto_stack (cinfo, TRUE);
+ args_onto_stack (cinfo);
/* Emit the signature cookie just before the implicit arguments */
add_int32_arg (cinfo, &cinfo->sig_cookie);
}
/* Fall through */
case MONO_TYPE_VALUETYPE: {
int j;
- int align_size;
int nwords = 0;
+ int has_offset = FALSE;
ArgInfo dummy_arg;
gint size, alignment;
MonoClass *klass;
alignment = mono_class_min_align (klass);
#if MIPS_PASS_STRUCTS_BY_VALUE
/* Need to do alignment if struct contains long or double */
- if (cinfo->stack_size & (alignment - 1)) {
- add_int32_arg (cinfo, &dummy_arg);
+ if (alignment > 4) {
+ if (cinfo->stack_size & (alignment - 1)) {
+ add_int32_arg (cinfo, &dummy_arg);
+ }
+ g_assert (!(cinfo->stack_size & (alignment - 1)));
}
- g_assert (!(cinfo->stack_size & (alignment - 1)));
#if 0
g_printf ("valuetype struct size=%d offset=%d align=%d\n",
mono_class_native_size (sig->params [i]->data.klass, NULL),
cinfo->stack_size, alignment);
#endif
- align_size = size;
- align_size += (sizeof (gpointer) - 1);
- align_size &= ~(sizeof (gpointer) - 1);
- nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
+ nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
+ g_assert (cinfo->args [n].size == 0);
+ g_assert (cinfo->args [n].vtsize == 0);
for (j = 0; j < nwords; ++j) {
- if (j == 0)
+ if (j == 0) {
add_int32_arg (cinfo, &cinfo->args [n]);
- else
+ if (cinfo->on_stack)
+ has_offset = TRUE;
+ } else {
add_int32_arg (cinfo, &dummy_arg);
+ if (!has_offset && cinfo->on_stack) {
+ cinfo->args [n].offset = dummy_arg.offset;
+ has_offset = TRUE;
+ }
+ }
if (cinfo->on_stack)
cinfo->args [n].vtsize += 1;
else
int size = sizeof (MonoTypedRef);
int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
cinfo->args [n].regtype = RegTypeStructByVal;
- if (cinfo->gr <= MIPS_LAST_ARG_REG) {
+ if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
int n_in_regs = rest >= nwords? nwords: rest;
cinfo->args [n].size = n_in_regs;
cinfo->args [n].vtsize = nwords - n_in_regs;
cinfo->args [n].reg = cinfo->gr;
cinfo->gr += n_in_regs;
+ cinfo->gr_passed = TRUE;
} else {
cinfo->args [n].size = 0;
cinfo->args [n].vtsize = nwords;
}
- cinfo->args [n].offset = MIPS_STACK_PARAM_OFFSET + cinfo->stack_size;
- g_print ("offset for arg %d at %d\n", n, MIPS_STACK_PARAM_OFFSET + cinfo->stack_size);
- cinfo->stack_size += nwords * sizeof (gpointer);
+ if (cinfo->args [n].vtsize > 0) {
+ if (!cinfo->on_stack)
+ args_onto_stack (cinfo);
+ g_assert(cinfo->on_stack);
+ cinfo->args [n].offset = cinfo->stack_size;
+ g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
+ cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
+ }
}
#else
add_int32_arg (cinfo, &cinfo->args[n]);
}
case MONO_TYPE_U8:
case MONO_TYPE_I8:
+ DEBUG(printf("8 bytes\n"));
cinfo->args [n].size = 8;
add_int64_arg (cinfo, &cinfo->args[n]);
n++;
break;
case MONO_TYPE_R4:
+ DEBUG(printf("R4\n"));
cinfo->args [n].size = 4;
add_float32_arg (cinfo, &cinfo->args[n]);
n++;
break;
case MONO_TYPE_R8:
+ DEBUG(printf("R8\n"));
cinfo->args [n].size = 8;
add_float64_arg (cinfo, &cinfo->args[n]);
n++;
}
/* align stack size to 16 */
- cinfo->stack_size = (cinfo->stack_size + 15) & ~15;
+ cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
cinfo->stack_usage = cinfo->stack_size;
return cinfo;
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
- cfg->flags |= MONO_CFG_HAS_SPILLUP;
+ /* spill down, we'll fix it in a separate pass */
+ // cfg->flags |= MONO_CFG_HAS_SPILLUP;
/* allow room for the vararg method args: void* and long/double */
if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
- cfg->param_area = MAX (cfg->param_area, 16);
+ /* a0-a3 always present */
+ cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
header = mono_method_get_header (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;
}
#endif
-#if EXTRA_STACK_SPACE
/* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
* args or return vals. Extra stack space avoids this in a lot of cases.
*/
- offset += 64;
-#endif
+ offset += EXTRA_STACK_SPACE;
+
/* Space for saved registers */
cfg->arch.iregs_offset = offset;
#if SAVE_ALL_REGS
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 EXTRA_STACK_SPACE
/* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
* args or return vals. Extra stack space avoids this in a lot of cases.
*/
- offset += 64;
-#endif
+ offset += EXTRA_STACK_SPACE;
/* saved float registers */
#if SAVE_FP_REGS
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)
/* Return struct-by-value results in a hidden first argument */
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
- cfg->ret->opcode = OP_REGOFFSET;
- cfg->ret->inst_c0 = mips_a0;
- cfg->ret->inst_offset = offset;
- cfg->ret->inst_basereg = frame_reg;
- offset += 4;
+ cfg->vret_addr->opcode = OP_REGOFFSET;
+ cfg->vret_addr->inst_c0 = mips_a0;
+ cfg->vret_addr->inst_offset = offset;
+ cfg->vret_addr->inst_basereg = frame_reg;
+ offset += SIZEOF_REGISTER;
}
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
inst->opcode = OP_REGOFFSET;
size = mono_type_size (arg_type, &align);
- /* Need to take references to R4 into account */
- /* If it's a single-precision float, allocate 8 bytes of stack for it */
- if ((arg_type->type == MONO_TYPE_R4) && !arg_type->byref) {
- align = 8;
- size = 8;
- }
- 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
+mono_arch_create_vars (MonoCompile *cfg)
+{
+ MonoMethodSignature *sig;
+
+ sig = mono_method_signature (cfg->method);
+
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
+ if (G_UNLIKELY (cfg->verbose_level > 1)) {
+ printf ("vret_addr = ");
+ mono_print_ins (cfg->vret_addr);
}
}
}
* etc.
* Issue: who does the spilling if needed, and when?
*/
-MonoCallInst*
-mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
- MonoInst *arg, *in;
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+ int sig_reg = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
+ mips_sp, cinfo->sig_cookie.offset, sig_reg);
+}
+
+void
+mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
+{
+ MonoInst *in, *ins;
MonoMethodSignature *sig;
int i, n;
CallInfo *cinfo;
- ArgInfo *ainfo;
+ int is_virtual = 0;
sig = call->signature;
n = sig->param_count + sig->hasthis;
call->used_iregs |= 1 << cinfo->struct_ret;
for (i = 0; i < n; ++i) {
- ainfo = cinfo->args + i;
- if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
- MonoInst *sig_arg;
- cfg->disable_aot = TRUE;
-
- MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
- sig_arg->inst_p0 = call->signature;
-
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- arg->inst_imm = cinfo->sig_cookie.offset;
- arg->inst_left = sig_arg;
-
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
- }
+ ArgInfo *ainfo = cinfo->args + i;
+ MonoType *t;
+
+ if (i >= sig->hasthis)
+ t = sig->params [i - sig->hasthis];
+ else
+ t = &mono_defaults.int_class->byval_arg;
+ t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
+
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
+ emit_sig_cookie (cfg, call, cinfo);
if (is_virtual && i == 0) {
/* the argument will be attached to the call instrucion */
in = call->args [i];
call->used_iregs |= 1 << ainfo->reg;
- } else {
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- in = call->args [i];
- arg->cil_code = in->cil_code;
- arg->inst_left = in;
- arg->inst_call = call;
- arg->type = in->type;
- /* prepend, we'll need to reverse them later */
- arg->next = call->out_args;
- call->out_args = arg;
- if (ainfo->regtype == RegTypeGeneral) {
- arg->backend.reg3 = ainfo->reg;
- call->used_iregs |= 1 << ainfo->reg;
- if (arg->type == STACK_I8)
- call->used_iregs |= 1 << (ainfo->reg + 1);
- } else if (ainfo->regtype == RegTypeStructByAddr) {
- /* FIXME: where is the data allocated? */
- arg->backend.reg3 = ainfo->reg;
- call->used_iregs |= 1 << ainfo->reg;
- } else if (ainfo->regtype == RegTypeStructByVal) {
- int cur_reg;
- MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
- /* mark the used regs */
- for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
- call->used_iregs |= 1 << (ainfo->reg + cur_reg);
- }
- arg->opcode = OP_OUTARG_VT;
- ai->reg = ainfo->reg;
- ai->size = ainfo->size;
- ai->vtsize = ainfo->vtsize;
- ai->offset = ainfo->offset;
- arg->backend.data = ai;
-#if 0
- g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
- ai->reg, ai->size, ai->vtsize, ai->offset);
+ continue;
+ }
+ 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 + 1;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
+
+ 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
#endif
- } else if (ainfo->regtype == RegTypeBase) {
- MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
- arg->opcode = OP_OUTARG_MEMBASE;
- ai->reg = ainfo->reg;
- ai->size = ainfo->size;
- ai->offset = ainfo->offset;
- arg->backend.data = ai;
- } else if (ainfo->regtype == RegTypeFP) {
- arg->opcode = OP_OUTARG_R8;
- arg->backend.reg3 = ainfo->reg;
- call->used_fregs |= 1 << ainfo->reg;
+ 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);
+ ins->sreg1 = freg;
+ 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_R8)) {
+ /* trying to load float value into int registers */
+ MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
+ ins->dreg = mono_alloc_ireg (cfg);
+ ins->sreg1 = in->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_MOVE);
+ ins->dreg = mono_alloc_ireg (cfg);
+ ins->sreg1 = in->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
+ }
+ } else if (ainfo->regtype == RegTypeStructByAddr) {
+ MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+ ins->opcode = OP_OUTARG_VT;
+ ins->sreg1 = in->dreg;
+ ins->klass = in->klass;
+ ins->inst_p0 = call;
+ ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+ memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+ MONO_ADD_INS (cfg->cbb, ins);
+ } else if (ainfo->regtype == RegTypeStructByVal) {
+ /* this is further handled in mono_arch_emit_outarg_vt () */
+ MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+ ins->opcode = OP_OUTARG_VT;
+ ins->sreg1 = in->dreg;
+ ins->klass = in->klass;
+ ins->inst_p0 = call;
+ ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+ memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+ MONO_ADD_INS (cfg->cbb, ins);
+ } else if (ainfo->regtype == RegTypeBase) {
+ if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
+ } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
+ if (t->type == MONO_TYPE_R8)
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
+ else
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
+ } else {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
+ }
+ } else if (ainfo->regtype == RegTypeFP) {
+ if (t->type == MONO_TYPE_VALUETYPE) {
+ /* this is further handled in mono_arch_emit_outarg_vt () */
+ MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+ ins->opcode = OP_OUTARG_VT;
+ ins->sreg1 = in->dreg;
+ ins->klass = in->klass;
+ ins->inst_p0 = call;
+ ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+ memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ cfg->flags |= MONO_CFG_HAS_FPOUT;
+ } else {
+ int dreg = mono_alloc_freg (cfg);
+
if (ainfo->size == 4) {
- arg->opcode = OP_OUTARG_R4;
- /* we reduce the precision */
- /*MonoInst *conv;
- MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
- conv->inst_left = arg->inst_left;
- arg->inst_left = conv;*/
+ MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_FMOVE);
+ ins->dreg = dreg;
+ ins->sreg1 = in->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
}
- } else {
- g_assert_not_reached ();
+
+ mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
+ cfg->flags |= MONO_CFG_HAS_FPOUT;
}
+ } else {
+ g_assert_not_reached ();
}
}
+
+ /* Emit the signature cookie in the case that there is no
+ additional argument */
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
+ emit_sig_cookie (cfg, call, cinfo);
+
+ if (cinfo->struct_ret) {
+ MonoInst *vtarg;
+
+ MONO_INST_NEW (cfg, vtarg, OP_MOVE);
+ vtarg->sreg1 = call->vret_var->dreg;
+ vtarg->dreg = mono_alloc_preg (cfg);
+ MONO_ADD_INS (cfg->cbb, vtarg);
+
+ mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
+ }
+#if 0
/*
* Reverse the call->out_args list.
*/
}
call->out_args = prev;
}
+#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;
/*
*/
g_free (cinfo);
- return call;
}
-static void
-peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
+void
+mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
{
- MonoInst *ins, *last_ins = NULL;
- ins = bb->code;
+ MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
+ ArgInfo *ainfo = ins->inst_p1;
+ int ovf_size = ainfo->vtsize;
+ int doffset = ainfo->offset;
+ int i, soffset, dreg;
- while (ins) {
+ if (ainfo->regtype == RegTypeStructByVal) {
+#if 1
+ if (cfg->verbose_level > 0) {
+ char* nm = mono_method_full_name (cfg->method, TRUE);
+ g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
+ nm, doffset, ainfo->size, ovf_size);
+ g_free (nm);
+ }
+#endif
- switch (ins->opcode) {
- case OP_MUL_IMM:
- /* remove unnecessary multiplication with 1 */
- if (ins->inst_imm == 1) {
- if (ins->dreg != ins->sreg1) {
- ins->opcode = OP_MOVE;
- } else {
- last_ins->next = ins->next;
- ins = ins->next;
- continue;
- }
+ soffset = 0;
+ for (i = 0; i < ainfo->size; ++i) {
+ 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_REGISTER;
+ }
+ if (ovf_size != 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);
+
+ if (ainfo->size == 4)
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
+ else
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
+ dreg = mono_alloc_freg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
+ mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
+ } else {
+ MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
+ MonoInst *load;
+ guint32 size;
+
+ /* FIXME: alignment? */
+ if (call->signature->pinvoke) {
+ size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
+ vtcopy->backend.is_pinvoke = 1;
+ } else {
+ size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
+ }
+ if (size > 0)
+ g_assert (ovf_size > 0);
+
+ EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
+ mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
+
+ if (ainfo->offset)
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
+ else
+ mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
+ }
+}
+
+void
+mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
+{
+ MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
+ 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_INST_NEW (cfg, ins, OP_SETLRET);
+ ins->sreg1 = val->dreg + 1;
+ ins->sreg2 = val->dreg + 2;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return;
+ }
+#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);
+}
+
+void
+mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins, *n, *last_ins = NULL;
+
+ if (cfg->verbose_level > 2)
+ g_print ("Basic block %d peephole pass 1\n", bb->block_num);
+
+ ins = bb->code;
+ MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
+ if (cfg->verbose_level > 2)
+ mono_print_ins_index (0, ins);
+
+ switch (ins->opcode) {
+#if 0
+ case OP_LOAD_MEMBASE:
+ case OP_LOADI4_MEMBASE:
+ /*
+ * OP_IADD reg2, reg1, const1
+ * OP_LOAD_MEMBASE const2(reg2), reg3
+ * ->
+ * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
+ */
+ if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
+ int const1 = last_ins->inst_imm;
+ int const2 = ins->inst_offset;
+
+ if (mips_is_imm16 (const1 + const2)) {
+ ins->inst_basereg = last_ins->sreg1;
+ ins->inst_offset = const1 + const2;
+ }
+ }
+ break;
+#endif
+
+ }
+ last_ins = ins;
+ ins = ins->next;
+ }
+ bb->last_ins = last_ins;
+}
+
+void
+mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins, *n, *last_ins = NULL;
+ ins = bb->code;
+
+ MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
+ MonoInst *last_ins = ins->prev;
+
+ switch (ins->opcode) {
+ case OP_MUL_IMM:
+ /* remove unnecessary multiplication with 1 */
+ if (ins->inst_imm == 1) {
+ if (ins->dreg != ins->sreg1) {
+ ins->opcode = OP_MOVE;
+ } else {
+ MONO_DELETE_INS (bb, ins);
+ continue;
+ }
} else {
int power2 = mono_is_power_of_two (ins->inst_imm);
if (power2 > 0) {
ins->inst_basereg == last_ins->inst_destbasereg &&
ins->inst_offset == last_ins->inst_offset) {
if (ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
+ MONO_DELETE_INS (bb, ins);
continue;
} else {
//static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
ins->inst_offset == last_ins->inst_offset) {
if (ins->dreg == last_ins->dreg) {
- last_ins->next = ins->next;
- ins = ins->next;
+ MONO_DELETE_INS (bb, ins);
continue;
} else {
ins->opcode = OP_MOVE;
if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
ins->inst_basereg == last_ins->inst_destbasereg &&
ins->inst_offset == last_ins->inst_offset) {
- ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
+ ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
ins->sreg1 = last_ins->sreg1;
}
break;
if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
ins->inst_basereg == last_ins->inst_destbasereg &&
ins->inst_offset == last_ins->inst_offset) {
- ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
+ ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
ins->sreg1 = last_ins->sreg1;
}
break;
- case CEE_CONV_I4:
- case CEE_CONV_U4:
+ case OP_ICONV_TO_I4:
+ case OP_ICONV_TO_U4:
case OP_MOVE:
- case OP_SETREG:
ins->opcode = OP_MOVE;
/*
* OP_MOVE reg, reg
*/
if (ins->dreg == ins->sreg1) {
- if (last_ins)
- last_ins->next = ins->next;
- ins = ins->next;
+ MONO_DELETE_INS (bb, ins);
continue;
}
/*
if (last_ins && last_ins->opcode == OP_MOVE &&
ins->sreg1 == last_ins->dreg &&
ins->dreg == last_ins->sreg1) {
- last_ins->next = ins->next;
- ins = ins->next;
+ MONO_DELETE_INS (bb, ins);
continue;
}
break;
bb->last_ins = last_ins;
}
-static inline InstList*
-inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
+void
+mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
{
- InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
- item->data = data;
- item->prev = NULL;
- item->next = list;
- if (list)
- list->prev = item;
- return item;
+ int tmp1 = -1;
+ int tmp2 = -1;
+ int tmp3 = -1;
+ int tmp4 = -1;
+ int tmp5 = -1;
+
+ switch (ins->opcode) {
+#if 0
+ case OP_LCOMPARE:
+ case OP_LCOMPARE_IMM:
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+#endif
+ case OP_LADD:
+ tmp1 = 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, ins->dreg+2, tmp1);
+ ins->opcode = OP_NOP;
+ break;
+
+ case OP_LADD_IMM:
+ tmp1 = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
+ 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;
+ break;
+
+ case OP_LSUB:
+ tmp1 = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+ 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;
+ break;
+
+ case OP_LSUB_IMM:
+ tmp1 = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
+ 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;
+ break;
+
+ case OP_LMUL:
+ case OP_LDIV:
+ case OP_LDIV_UN:
+ case OP_LREM:
+ case OP_LREM_UN:
+ case OP_LSHL:
+ case OP_LSHR:
+ case OP_LSHR_UN:
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+
+ case OP_LNEG:
+ tmp1 = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
+ 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;
+ break;
+
+#if 0
+ case OP_LNOT:
+#endif
+#if 0
+ case OP_LCONV_TO_I1:
+ case OP_LCONV_TO_I2:
+ case OP_LCONV_TO_I4:
+ case OP_LCONV_TO_I8:
+ case OP_LCONV_TO_R4:
+ case OP_LCONV_TO_R8:
+ case OP_LCONV_TO_U4:
+ case OP_LCONV_TO_U8:
+ case OP_LCONV_TO_U2:
+ case OP_LCONV_TO_U1:
+ case OP_LCONV_TO_I:
+ case OP_LCONV_TO_OVF_I:
+ case OP_LCONV_TO_OVF_U:
+#endif
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+
+ case OP_LADD_OVF:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+ tmp3 = mono_alloc_ireg (cfg);
+ tmp4 = mono_alloc_ireg (cfg);
+ tmp5 = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+
+ /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
+ MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
+
+ /* add the high 32-bits, and add in the carry from the low 32-bits */
+ 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, tmp5, ins->dreg+2);
+
+ /* Overflow happens if
+ * neg + neg = pos or
+ * pos + pos = neg
+ * XOR of the high bits returns 0 if the signs match
+ * XOR of that with the high bit of the result return 1 if overflow.
+ */
+
+ /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
+
+ /* set tmp2 = 0 if bit31 of results matches is different than the operands */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
+ MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
+
+ /* OR(tmp1, tmp2) = 0 if both conditions are true */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
+
+ /* Now, if (tmp4 == 0) then overflow */
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
+ ins->opcode = OP_NOP;
+ 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");
+ ins->opcode = OP_NOP;
+ break;
+
+ case OP_LMUL_OVF:
+ case OP_LMUL_OVF_UN:
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+
+ case OP_LSUB_OVF:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+ tmp3 = mono_alloc_ireg (cfg);
+ tmp4 = mono_alloc_ireg (cfg);
+ tmp5 = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, 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, tmp5);
+
+ /* Overflow happens if
+ * neg - pos = pos or
+ * pos - neg = neg
+ * XOR of bit31 of the lhs & rhs = 1 if the signs are different
+ *
+ * tmp1 = (lhs ^ rhs)
+ * tmp2 = (lhs ^ result)
+ * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
+ */
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
+
+ /* Now, if (tmp4 == 1) then overflow */
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
+ ins->opcode = OP_NOP;
+ break;
+
+ case OP_LSUB_OVF_UN:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
+ 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);
+
+ 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;
+ break;
+#if 0
+ case OP_LCONV_TO_OVF_I1_UN:
+ case OP_LCONV_TO_OVF_I2_UN:
+ case OP_LCONV_TO_OVF_I4_UN:
+ case OP_LCONV_TO_OVF_I8_UN:
+ case OP_LCONV_TO_OVF_U1_UN:
+ case OP_LCONV_TO_OVF_U2_UN:
+ case OP_LCONV_TO_OVF_U4_UN:
+ case OP_LCONV_TO_OVF_U8_UN:
+ case OP_LCONV_TO_OVF_I_UN:
+ case OP_LCONV_TO_OVF_U_UN:
+ case OP_LCONV_TO_OVF_I1:
+ case OP_LCONV_TO_OVF_U1:
+ case OP_LCONV_TO_OVF_I2:
+ case OP_LCONV_TO_OVF_U2:
+ case OP_LCONV_TO_OVF_I4:
+ case OP_LCONV_TO_OVF_U4:
+ case OP_LCONV_TO_OVF_I8:
+ case OP_LCONV_TO_OVF_U8:
+#endif
+ case OP_LCEQ:
+ case OP_LCGT:
+ case OP_LCGT_UN:
+ case OP_LCLT:
+ case OP_LCLT_UN:
+#if 0
+ case OP_LCONV_TO_R_UN:
+ case OP_LCONV_TO_U:
+#endif
+ case OP_LMUL_IMM:
+ case OP_LSHL_IMM:
+ case OP_LSHR_IMM:
+ case OP_LSHR_UN_IMM:
+ case OP_LDIV_IMM:
+ case OP_LDIV_UN_IMM:
+ case OP_LREM_IMM:
+ case OP_LREM_UN_IMM:
+ case OP_LBEQ:
+ case OP_LBGE:
+ case OP_LBGT:
+ case OP_LBLE:
+ case OP_LBLT:
+ case OP_LBNE_UN:
+ case OP_LBGE_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:
+ 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);
+ ins->opcode = OP_NOP;
+ break;
+
+ case OP_LMIN_UN:
+ case OP_LMAX_UN:
+ case OP_LMIN:
+ case OP_LMAX:
+ mono_print_ins (ins);
+ g_assert_not_reached ();
+
+ default:
+ break;
+ }
}
-static void
-insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
+void
+mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
{
- if (ins == NULL) {
- ins = bb->code;
- bb->code = to_insert;
- to_insert->next = ins;
- } else {
- to_insert->next = ins->next;
- ins->next = to_insert;
+ int tmp1 = -1;
+ int tmp2 = -1;
+ int tmp3 = -1;
+ int tmp4 = -1;
+ int tmp5 = -1;
+
+ switch (ins->opcode) {
+ case OP_IADD_OVF:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+ tmp3 = mono_alloc_ireg (cfg);
+ tmp4 = mono_alloc_ireg (cfg);
+ tmp5 = mono_alloc_ireg (cfg);
+
+ /* add the operands */
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
+
+ /* Overflow happens if
+ * neg + neg = pos or
+ * pos + pos = neg
+ *
+ * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
+ * XOR of the high bit returns 0 if the signs match
+ * XOR of that with the high bit of the result return 1 if overflow.
+ */
+
+ /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
+
+ /* set tmp2 = 0 if bit31 of results matches is different than the operands */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
+ MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
+
+ /* OR(tmp1, tmp2) = 0 if both conditions are true */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
+
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
+
+ /* Now, if (tmp4 == 0) then overflow */
+ MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
+ ins->opcode = OP_NOP;
+ 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");
+ ins->opcode = OP_NOP;
+ break;
+
+ case OP_ISUB_OVF:
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+ tmp3 = mono_alloc_ireg (cfg);
+ tmp4 = mono_alloc_ireg (cfg);
+ tmp5 = mono_alloc_ireg (cfg);
+
+ /* add the operands */
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
+
+ /* Overflow happens if
+ * neg - pos = pos or
+ * pos - neg = neg
+ * XOR of bit31 of the lhs & rhs = 1 if the signs are different
+ *
+ * tmp1 = (lhs ^ rhs)
+ * tmp2 = (lhs ^ result)
+ * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
+ */
+
+ /* tmp3 = 1 if the signs of the two inputs differ */
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
+ 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;
+ break;
+
+ case OP_ISUB_OVF_UN:
+ tmp1 = mono_alloc_ireg (cfg);
+
+ 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;
}
-}
-#define NEW_INS(cfg,dest,op) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = (op); \
- insert_after_ins (bb, last_ins, (dest)); \
- } while (0)
+}
static int
map_to_reg_reg_op (int op)
{
switch (op) {
case OP_ADD_IMM:
- return CEE_ADD;
+ return OP_IADD;
case OP_SUB_IMM:
- return CEE_SUB;
+ return OP_ISUB;
case OP_AND_IMM:
- return CEE_AND;
+ return OP_IAND;
case OP_COMPARE_IMM:
return OP_COMPARE;
+ case OP_ICOMPARE_IMM:
+ return OP_ICOMPARE;
+ case OP_LCOMPARE_IMM:
+ return OP_LCOMPARE;
case OP_ADDCC_IMM:
- return OP_ADDCC;
+ return OP_IADDCC;
case OP_ADC_IMM:
- return OP_ADC;
+ return OP_IADC;
case OP_SUBCC_IMM:
- return OP_SUBCC;
+ return OP_ISUBCC;
case OP_SBB_IMM:
- return OP_SBB;
+ return OP_ISBB;
case OP_OR_IMM:
- return CEE_OR;
+ return OP_IOR;
case OP_XOR_IMM:
- return CEE_XOR;
+ return OP_IXOR;
case OP_MUL_IMM:
- return CEE_MUL;
+ return OP_IMUL;
case OP_LOAD_MEMBASE:
return OP_LOAD_MEMINDEX;
case OP_LOADI4_MEMBASE:
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);
+}
+
+static int
+map_to_mips_op (int op)
+{
+ switch (op) {
+ case OP_FBEQ:
+ return OP_MIPS_FBEQ;
+ case OP_FBGE:
+ return OP_MIPS_FBGE;
+ case OP_FBGT:
+ return OP_MIPS_FBGT;
+ case OP_FBLE:
+ return OP_MIPS_FBLE;
+ case OP_FBLT:
+ return OP_MIPS_FBLT;
+ case OP_FBNE_UN:
+ return OP_MIPS_FBNE;
+ case OP_FBGE_UN:
+ return OP_MIPS_FBGE_UN;
+ case OP_FBGT_UN:
+ return OP_MIPS_FBGT_UN;
+ case OP_FBLE_UN:
+ return OP_MIPS_FBLE_UN;
+ case OP_FBLT_UN:
+ return OP_MIPS_FBLT_UN;
+
+ case OP_FCEQ:
+ case OP_FCGT:
+ case OP_FCGT_UN:
+ case OP_FCLT:
+ case OP_FCLT_UN:
+ default:
+ g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
+ g_assert_not_reached ();
}
- g_assert_not_reached ();
}
+#define NEW_INS(cfg,after,dest,op) do { \
+ MONO_INST_NEW((cfg), (dest), (op)); \
+ mono_bblock_insert_after_ins (bb, (after), (dest)); \
+ } while (0)
+
+#define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
+ MonoInst *temp; \
+ MONO_INST_NEW(cfg, temp, (op)); \
+ mono_bblock_insert_after_ins (bb, (pos), temp); \
+ temp->dreg = (_dreg); \
+ temp->sreg1 = (_sreg1); \
+ temp->sreg2 = (_sreg2); \
+ pos = temp; \
+ } while (0)
+
+#define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
+ MonoInst *temp; \
+ MONO_INST_NEW(cfg, temp, (op)); \
+ mono_bblock_insert_after_ins (bb, (pos), temp); \
+ temp->dreg = (_dreg); \
+ temp->sreg1 = (_sreg1); \
+ temp->inst_c0 = (_imm); \
+ pos = temp; \
+ } while (0)
+
/*
* Remove from the instruction list the instructions that can't be
* represented with very simple instructions with no register
* requirements.
*/
-static void
+void
mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
{
MonoInst *ins, *next, *temp, *last_ins = NULL;
int imm;
- /* setup the virtual reg allocator */
- if (bb->max_vreg > cfg->rs->next_vreg)
- cfg->rs->next_vreg = bb->max_vreg;
+#if 1
+ if (cfg->verbose_level > 2) {
+ int idx = 0;
- ins = bb->code;
- while (ins) {
+ g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ mono_print_ins_index (idx++, ins);
+ }
+
+ }
+#endif
+
+ MONO_BB_FOR_EACH_INS (bb, ins) {
loop_start:
switch (ins->opcode) {
- case OP_ADD_IMM:
- case OP_ADDCC_IMM:
- if (!mips_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, temp, OP_ICONST);
+ 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)))) {
+ ins->opcode = OP_NOP;
+ 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;
+ break;
+ }
+ if (ins->inst_imm) {
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
+ temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
+ last_ins = temp;
}
- break;
+ else {
+ ins->sreg2 = mips_zero;
+ }
+ if (ins->opcode == OP_COMPARE_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:
+ case OP_IDIV_IMM:
+ case OP_IREM_IMM:
+ case OP_IREM_UN_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;
+ if (ins->opcode == OP_IDIV_IMM)
+ ins->opcode = OP_IDIV;
+ else if (ins->opcode == OP_IREM_IMM)
+ ins->opcode = OP_IREM;
+ else if (ins->opcode == OP_IDIV_UN_IMM)
+ ins->opcode = OP_IDIV_UN;
+ else if (ins->opcode == OP_IREM_UN_IMM)
+ ins->opcode = OP_IREM_UN;
+ last_ins = temp;
+ /* handle rem separately */
+ goto loop_start;
+
#if 0
- case OP_SUB_IMM:
- if (!mips_is_imm16 (-ins->inst_imm)) {
- NEW_INS (cfg, temp, OP_ICONST);
+ case OP_AND_IMM:
+ case OP_OR_IMM:
+ case OP_XOR_IMM:
+ if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
+ temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
ins->opcode = map_to_reg_reg_op (ins->opcode);
}
break;
#endif
-#if 0
case OP_AND_IMM:
+ case OP_IAND_IMM:
case OP_OR_IMM:
+ case OP_IOR_IMM:
case OP_XOR_IMM:
- if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
- NEW_INS (cfg, temp, OP_ICONST);
+ case OP_IXOR_IMM:
+ /* unsigned 16 bit immediate */
+ if (ins->inst_imm & 0xffff0000) {
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
+ temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
ins->opcode = map_to_reg_reg_op (ins->opcode);
}
break;
-#endif
-#if 0
- case OP_SBB_IMM:
- case OP_SUBCC_IMM:
- case OP_ADC_IMM:
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
+
+ case OP_IADD_IMM:
+ case OP_ADD_IMM:
+ case OP_ADDCC_IMM:
+ /* signed 16 bit immediate */
+ 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);
+ }
break;
-#endif
-#if 0
- case OP_COMPARE_IMM:
- if (compare_opcode_is_unsigned (ins->next->opcode)) {
- if (!ppc_is_uimm16 (ins->inst_imm)) {
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
- }
- } else {
- if (!ppc_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- ins->sreg2 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
- }
+
+ 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;
+ temp->dreg = mono_alloc_ireg (cfg);
+ ins->sreg2 = temp->dreg;
+ ins->opcode = map_to_reg_reg_op (ins->opcode);
}
break;
-#endif
-#if 0
+
case OP_MUL_IMM:
+ case OP_IMUL_IMM:
if (ins->inst_imm == 1) {
ins->opcode = OP_MOVE;
break;
ins->inst_imm = imm;
break;
}
- if (!ppc_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- 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;
-#endif
-#if 0
+
+ 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_LOADI4_MEMBASE:
case OP_LOADU4_MEMBASE:
* represented as an ad_imm + a load with a smaller offset
* that fits. We just do the first for now, optimize later.
*/
- if (ppc_is_imm16 (ins->inst_offset))
+ if (mips_is_imm16 (ins->inst_offset))
break;
- NEW_INS (cfg, temp, OP_ICONST);
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
temp->inst_c0 = ins->inst_offset;
- temp->dreg = mono_regstate_next_int (cfg->rs);
+ temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
ins->opcode = map_to_reg_reg_op (ins->opcode);
break;
-#endif
+
case OP_STORE_MEMBASE_IMM:
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);
}
+ else {
+ 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 = map_to_reg_reg_op (ins->opcode);
+ last_ins = temp;
+ goto loop_start; /* make it handle the possibly big ins->inst_offset */
+ }
+ 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;
+
#if 0
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- ins->sreg1 = temp->dreg;
- ins->opcode = map_to_reg_reg_op (ins->opcode);
+ case OP_R8CONST:
+ case OP_R4CONST:
+ NEW_INS (cfg, last_ins, temp, OP_ICONST);
+ temp->inst_c0 = (guint32)ins->inst_p0;
+ temp->dreg = mono_alloc_ireg (cfg);
+ ins->inst_basereg = temp->dreg;
+ ins->inst_offset = 0;
+ ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
last_ins = temp;
- goto loop_start; /* make it handle the possibly big ins->inst_offset */
+ /* make it handle the possibly big ins->inst_offset
+ * 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;
+ 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;
+ break;
+
+ case OP_IBGE:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBGE_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBLT:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBLT_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBLE:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBLE_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBGT:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_IBGT_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
+ last_ins->dreg = mono_alloc_ireg (cfg);
+ INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
+ break;
+
+ case OP_CEQ:
+ case OP_ICEQ:
+ g_assert (ins_is_compare(last_ins));
+ last_ins->opcode = OP_IXOR;
+ last_ins->dreg = mono_alloc_ireg(cfg);
+ INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
+ break;
+
+ case OP_CLT:
+ case OP_ICLT:
+ INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
+ last_ins->opcode = OP_NOP;
+ 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;
+ break;
+
+ case OP_CGT:
+ case OP_ICGT:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_CGT_UN:
+ case OP_ICGT_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_EQ:
+ case OP_COND_EXC_IEQ:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_GE:
+ case OP_COND_EXC_IGE:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_GT:
+ case OP_COND_EXC_IGT:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_LE:
+ case OP_COND_EXC_ILE:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_LT:
+ case OP_COND_EXC_ILT:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_NE_UN:
+ case OP_COND_EXC_INE_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ 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_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_UN, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_LE_UN:
+ case OP_COND_EXC_ILE_UN:
+ g_assert (ins_is_compare(last_ins));
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_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_UN, last_ins->sreg1, last_ins->sreg2);
+ MONO_DELETE_INS(bb, last_ins);
+ break;
+
+ case OP_COND_EXC_OV:
+ case OP_COND_EXC_IOV: {
+ int tmp1, tmp2, tmp3, tmp4, tmp5;
+ MonoInst *pos = last_ins;
+
+ /* Overflow happens if
+ * neg + neg = pos or
+ * pos + pos = neg
+ *
+ * (bit31s of operands match) AND (bit31 of operand
+ * != bit31 of result)
+ * XOR of the high bit returns 0 if the signs match
+ * XOR of that with the high bit of the result return 1
+ * if overflow.
+ */
+ g_assert (last_ins->opcode == OP_IADC);
+
+ tmp1 = mono_alloc_ireg (cfg);
+ tmp2 = mono_alloc_ireg (cfg);
+ tmp3 = mono_alloc_ireg (cfg);
+ tmp4 = mono_alloc_ireg (cfg);
+ tmp5 = mono_alloc_ireg (cfg);
+
+ /* tmp1 = 0 if the signs of the two inputs match, else 1 */
+ INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
+
+ /* set tmp2 = 0 if bit31 of results matches is different than the operands */
+ INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
+ INS (pos, OP_INOT, tmp3, tmp2, -1);
+
+ /* OR(tmp1, tmp2) = 0 if both conditions are true */
+ INS (pos, OP_IOR, tmp4, tmp3, tmp1);
+ INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
+
+ /* Now, if (tmp5 == 0) then overflow */
+ INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
+ ins->dreg = -1;
+ break;
+ }
+
+ case OP_COND_EXC_NO:
+ case OP_COND_EXC_INO:
+ g_assert_not_reached ();
+ break;
+
+ case OP_COND_EXC_C:
+ case OP_COND_EXC_IC:
+ g_assert_not_reached ();
+ break;
+
+ case OP_COND_EXC_NC:
+ case OP_COND_EXC_INC:
+ g_assert_not_reached ();
break;
+
}
last_ins = ins;
- ins = ins->next;
}
bb->last_ins = last_ins;
- bb->max_vreg = cfg->rs->next_vreg;
-}
+ bb->max_vreg = cfg->next_vreg;
+
+#if 1
+ if (cfg->verbose_level > 2) {
+ int idx = 0;
+
+ g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ mono_print_ins_index (idx++, ins);
+ }
+
+ }
+#endif
-void
-mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- if (!bb->code)
- return;
- mono_arch_lowering_pass (cfg, bb);
- mono_local_regalloc (cfg, bb);
}
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
return code;
}
+/*
+ * emit_load_volatile_arguments:
+ *
+ * Load volatile arguments from the stack to the original input registers.
+ * Required before a tail call.
+ */
+static guint8 *
+emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
+{
+ MonoMethod *method = cfg->method;
+ MonoMethodSignature *sig;
+ MonoInst *inst;
+ CallInfo *cinfo;
+ int i;
+
+ sig = mono_method_signature (method);
+ cinfo = calculate_sizes (sig, sig->pinvoke);
+ if (cinfo->struct_ret) {
+ ArgInfo *ainfo = &cinfo->ret;
+ inst = cfg->vret_addr;
+ mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ }
+
+ for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+ ArgInfo *ainfo = cinfo->args + i;
+ inst = cfg->args [i];
+ if (inst->opcode == OP_REGVAR) {
+ if (ainfo->regtype == RegTypeGeneral)
+ MIPS_MOVE (code, ainfo->reg, inst->dreg);
+ else if (ainfo->regtype == RegTypeFP)
+ g_assert_not_reached();
+ else if (ainfo->regtype == RegTypeBase) {
+ /* do nothing */
+ } else
+ g_assert_not_reached ();
+ } else {
+ if (ainfo->regtype == RegTypeGeneral) {
+ g_assert (mips_is_imm16 (inst->inst_offset));
+ switch (ainfo->size) {
+ case 1:
+ mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ break;
+ case 2:
+ mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ break;
+ case 0: /* XXX */
+ case 4:
+ mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ break;
+ case 8:
+ mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ } 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 _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_not_reached ();
+ } else if (ainfo->regtype == RegTypeStructByVal) {
+ int i;
+ int doffset = inst->inst_offset;
+
+ g_assert (mips_is_imm16 (inst->inst_offset));
+ 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_REGISTER;
+ }
+ } else if (ainfo->regtype == RegTypeStructByAddr) {
+ g_assert (mips_is_imm16 (inst->inst_offset));
+ mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
+ } else
+ g_assert_not_reached ();
+ }
+ }
+
+ g_free (cinfo);
+
+ return code;
+}
+
+static guint8*
+emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
+{
+ int size = cfg->param_area;
+
+ size += MONO_ARCH_FRAME_ALIGNMENT - 1;
+ size &= -MONO_ARCH_FRAME_ALIGNMENT;
+
+ if (!size)
+ return code;
+#if 0
+ ppc_lwz (code, ppc_r0, 0, ppc_sp);
+ if (ppc_is_imm16 (-size)) {
+ ppc_stwu (code, ppc_r0, -size, ppc_sp);
+ } else {
+ ppc_load (code, ppc_r11, -size);
+ ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
+ }
+#endif
+ return code;
+}
+
+static guint8*
+emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
+{
+ int size = cfg->param_area;
+
+ size += MONO_ARCH_FRAME_ALIGNMENT - 1;
+ size &= -MONO_ARCH_FRAME_ALIGNMENT;
+
+ if (!size)
+ return code;
+#if 0
+ ppc_lwz (code, ppc_r0, 0, ppc_sp);
+ if (ppc_is_imm16 (size)) {
+ ppc_stwu (code, ppc_r0, size, ppc_sp);
+ } else {
+ ppc_load (code, ppc_r11, size);
+ ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
+ }
+#endif
+ return code;
+}
+
void
mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
{
int max_len, cpos;
int ins_cnt = 0;
- if (cfg->opt & MONO_OPT_PEEPHOLE)
- peephole_pass (cfg, bb);
-
/* we don't align basic blocks of loops on mips */
if (cfg->verbose_level > 2)
mips_sw (code, mips_temp, mips_at, 0);
}
#endif
- ins = bb->code;
- while (ins) {
+ MONO_BB_FOR_EACH_INS (bb, ins) {
offset = code - cfg->native_code;
max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
mono_debug_record_line_number (cfg, ins, offset);
if (cfg->verbose_level > 2) {
g_print (" @ 0x%x\t", offset);
- mono_print_ins (ins_cnt++, ins);
+ mono_print_ins_index (ins_cnt++, ins);
}
+ /* Check for virtual regs that snuck by */
+ g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
switch (ins->opcode) {
+ case OP_RELAXED_NOP:
+ case OP_NOP:
+ case OP_DUMMY_USE:
+ case OP_DUMMY_STORE:
+ case OP_NOT_REACHED:
+ case OP_NOT_NULL:
+ break;
case OP_TLS_GET:
g_assert_not_reached();
#if 0
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 CEE_LDIND_I:
- case CEE_LDIND_I4:
- case CEE_LDIND_U4:
- g_assert_not_reached ();
- //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
+ 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:
mips_lhu (code, ins->dreg, mips_at, 0);
}
break;
- case CEE_CONV_I1:
+ case OP_ICONV_TO_I1:
mips_sll (code, mips_at, ins->sreg1, 24);
mips_sra (code, ins->dreg, mips_at, 24);
break;
- case CEE_CONV_I2:
+ case OP_ICONV_TO_I2:
mips_sll (code, mips_at, ins->sreg1, 16);
mips_sra (code, ins->dreg, mips_at, 16);
break;
- case CEE_CONV_U1:
+ case OP_ICONV_TO_U1:
mips_andi (code, ins->dreg, ins->sreg1, 0xff);
break;
- case CEE_CONV_U2:
+ case OP_ICONV_TO_U2:
mips_sll (code, mips_at, ins->sreg1, 16);
mips_srl (code, ins->dreg, mips_at, 16);
break;
g_assert (mips_is_imm16 (ins->inst_imm));
mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case OP_COMPARE_IMM:
- g_assert_not_reached ();
- break;
- case OP_COMPARE:
- g_assert_not_reached ();
- break;
case OP_BREAK:
mips_break (code, 0xfd);
break;
- case OP_ADDCC:
- g_assert_not_reached ();
- break;
- case CEE_ADD:
+ case OP_IADD:
mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
- case OP_ADC:
- g_assert_not_reached ();
- break;
- case OP_ADDCC_IMM:
- g_assert_not_reached ();
+ case OP_LADD:
+ mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+
case OP_ADD_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);
- }
- break;
- case OP_ADC_IMM:
- g_assert_not_reached ();
- break;
- case CEE_ADD_OVF:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case CEE_ADD_OVF_UN:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case CEE_SUB_OVF:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case CEE_SUB_OVF_UN:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case OP_ADD_OVF_CARRY:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case OP_ADD_OVF_UN_CARRY:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case OP_SUB_OVF_CARRY:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case OP_SUB_OVF_UN_CARRY:
- /* rewritten in .brg file */
- g_assert_not_reached ();
- break;
- case OP_SUBCC:
- /* rewritten in .brg file */
- g_assert_not_reached ();
+ case OP_IADD_IMM:
+ g_assert (mips_is_imm16 (ins->inst_imm));
+ mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case OP_SUBCC_IMM:
- /* rewritten in .brg file */
- g_assert_not_reached ();
+ case OP_LADD_IMM:
+ g_assert (mips_is_imm16 (ins->inst_imm));
+ mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case CEE_SUB:
+
+ case OP_ISUB:
mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
- case OP_SBB:
- g_assert_not_reached ();
+ 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_SBB_IMM:
- g_assert_not_reached ();
+
+ 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 CEE_AND:
+
+ case OP_IAND:
+ case OP_LAND:
mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+
case OP_AND_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_IAND_IMM:
+ case OP_LAND_IMM:
+ g_assert (!(ins->inst_imm & 0xffff0000));
+ mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case CEE_DIV:
- case CEE_REM: {
+
+ case OP_IDIV:
+ case OP_IREM: {
guint32 *divisor_is_m1;
guint32 *divisor_is_zero;
/* */
mips_addiu (code, mips_at, mips_zero, 0xffff);
- divisor_is_m1 = (guint32 *)code;
+ divisor_is_m1 = (guint32 *)(void *)code;
mips_bne (code, ins->sreg2, mips_at, 0);
mips_nop (code);
mips_patch (divisor_is_m1, (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_div (code, ins->sreg1, ins->sreg2);
- if (ins->opcode == CEE_DIV)
+ if (ins->opcode == OP_IDIV)
mips_mflo (code, ins->dreg);
else
mips_mfhi (code, ins->dreg);
break;
}
- case CEE_DIV_UN: {
+ case OP_IDIV_UN:
+ case OP_IREM_UN: {
guint32 *divisor_is_zero = (guint32 *)(void *)code;
/* Put divide in branch delay slot (NOT YET) */
mips_patch (divisor_is_zero, (guint32)code);
mips_divu (code, ins->sreg1, ins->sreg2);
- mips_mflo (code, ins->dreg);
+ if (ins->opcode == OP_IDIV_UN)
+ mips_mflo (code, ins->dreg);
+ else
+ mips_mfhi (code, ins->dreg);
break;
}
case OP_DIV_IMM:
#endif
g_assert_not_reached();
break;
- case CEE_REM_UN: {
- guint32 *divisor_is_zero = (guint32 *)(void *)code;
-
- /* Put divide in branch delay slot (NOT YET) */
- mips_bne (code, ins->sreg2, mips_zero, 0);
- mips_nop (code);
-
- /* Divide by zero -- throw exception */
- EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
-
- mips_patch (divisor_is_zero, (guint32)code);
- mips_divu (code, ins->sreg1, ins->sreg2);
- mips_mfhi (code, ins->dreg);
- break;
- }
case OP_REM_IMM:
g_assert_not_reached ();
- case CEE_OR:
+ case OP_IOR:
mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_OR_IMM:
- if (mips_is_imm16 (ins->inst_imm)) {
- mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
- } else {
- mips_load_const (code, mips_at, ins->inst_imm);
- mips_or (code, ins->dreg, ins->sreg1, mips_at);
- }
+ case OP_IOR_IMM:
+ g_assert (!(ins->inst_imm & 0xffff0000));
+ mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case CEE_XOR:
+ case OP_IXOR:
mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_XOR_IMM:
+ case OP_IXOR_IMM:
/* unsigned 16-bit immediate */
- if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
- mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
- } else {
- mips_load_const (code, mips_at, ins->inst_imm);
- mips_xor (code, ins->dreg, ins->sreg1, mips_at);
- }
- break;
- case OP_MIPS_XORI:
- g_assert (mips_is_imm16 (ins->inst_imm));
+ g_assert (!(ins->inst_imm & 0xffff0000));
mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
- case CEE_SHL:
+ case OP_ISHL:
mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_SHL_IMM:
+ case OP_ISHL_IMM:
mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
break;
- case CEE_SHR:
+ 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 CEE_SHR_UN:
+ 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 CEE_NOT:
+ 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 CEE_NEG:
+ case OP_INEG:
mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
break;
- case CEE_MUL:
-#if 1
+ case OP_LNEG:
+ mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
+ break;
+ case OP_IMUL:
+#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:
- 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;
- case CEE_MUL_OVF: {
+#endif
+ case OP_IMUL_OVF: {
guint32 *patch;
mips_mult (code, ins->sreg1, ins->sreg2);
mips_mflo (code, ins->dreg);
mips_patch (patch, (guint32)code);
break;
}
- case CEE_MUL_OVF_UN:
+ case OP_IMUL_OVF_UN:
#if 0
mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
#else
/* XXX - Throw exception if we overflowed */
break;
case OP_ICONST:
- case OP_SETREGIMM:
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 CEE_CONV_I4:
- case CEE_CONV_U4:
+ case OP_ICONV_TO_I4:
+ case OP_ICONV_TO_U4:
case OP_MOVE:
- case OP_SETREG:
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);
- }
- break;
- case OP_SETFREG:
- if (ins->dreg != ins->sreg1) {
- mips_fmovd (code, ins->dreg, 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);
+
/*
* Pop our stack, then jump to specified method (tail-call)
* Keep in sync with mono_arch_emit_epilog
case OP_FCALL:
case OP_LCALL:
case OP_VCALL:
+ case OP_VCALL2:
case OP_VOIDCALL:
- case CEE_CALL:
+ case OP_CALL:
case OP_FCALL_REG:
case OP_LCALL_REG:
case OP_VCALL_REG:
+ case OP_VCALL2_REG:
case OP_VOIDCALL_REG:
case OP_CALL_REG:
case OP_FCALL_MEMBASE:
case OP_LCALL_MEMBASE:
case OP_VCALL_MEMBASE:
+ case OP_VCALL2_MEMBASE:
case OP_VOIDCALL_MEMBASE:
case OP_CALL_MEMBASE:
+ call = (MonoCallInst*)ins;
switch (ins->opcode) {
case OP_FCALL:
case OP_LCALL:
case OP_VCALL:
+ case OP_VCALL2:
case OP_VOIDCALL:
- case CEE_CALL:
- call = (MonoCallInst*)ins;
+ case OP_CALL:
if (ins->flags & MONO_INST_HAS_METHOD)
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
else
case OP_FCALL_REG:
case OP_LCALL_REG:
case OP_VCALL_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);
break;
case OP_FCALL_MEMBASE:
case OP_LCALL_MEMBASE:
case OP_VCALL_MEMBASE:
+ case OP_VCALL2_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;
- case OP_OUTARG:
- g_assert_not_reached ();
+#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 CEE_RET:
- mips_jr (code, mips_ra);
- mips_nop (code);
- break;
case OP_THROW: {
gpointer addr = mono_arch_get_throw_exception();
mips_move (code, mips_a0, ins->sreg1);
mips_break (code, 0xfb);
break;
}
- case OP_START_HANDLER:
+ case OP_START_HANDLER: {
/*
- * The START_HANDLER instruction marks the beginning of a handler
- * block. It is called using a call instruction, so mips_ra contains
- * the return address. Since the handler executes in the same stack
- * frame as the method itself, we can't use save/restore to save
- * the return address. Instead, we save it into a dedicated
- * variable.
+ * The START_HANDLER instruction marks the beginning of
+ * a handler block. It is called using a call
+ * instruction, so mips_ra contains the return address.
+ * Since the handler executes in the same stack frame
+ * as the method itself, we can't use save/restore to
+ * save the return address. Instead, we save it into
+ * a dedicated variable.
*/
- if (mips_is_imm16 (ins->inst_left->inst_offset)) {
- mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ g_assert (spvar->inst_basereg != mips_sp);
+ code = emit_reserve_param_area (cfg, code);
+
+ if (mips_is_imm16 (spvar->inst_offset)) {
+ mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
} else {
- mips_load_const (code, mips_at, ins->inst_left->inst_offset);
- mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
+ mips_load_const (code, mips_at, spvar->inst_offset);
+ mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
mips_sw (code, mips_ra, mips_at, 0);
}
break;
- case OP_ENDFILTER:
+ }
+ case OP_ENDFILTER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ g_assert (spvar->inst_basereg != mips_sp);
+ code = emit_unreserve_param_area (cfg, code);
+
if (ins->sreg1 != mips_v0)
- mips_move (code, mips_v0, ins->sreg1);
- if (mips_is_imm16 (ins->inst_left->inst_offset)) {
- mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+ 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_load_const (code, mips_at, ins->inst_left->inst_offset);
- mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
+ mips_load_const (code, mips_at, spvar->inst_offset);
+ mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
mips_lw (code, mips_ra, mips_at, 0);
}
mips_jr (code, mips_ra);
mips_nop (code);
break;
- case OP_ENDFINALLY:
- mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
+ }
+ case OP_ENDFINALLY: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ g_assert (spvar->inst_basereg != mips_sp);
+ code = emit_unreserve_param_area (cfg, code);
+ mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
mips_jalr (code, mips_t9, mips_ra);
mips_nop (code);
break;
+ }
case OP_CALL_HANDLER:
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
mips_lui (code, mips_t9, mips_zero, 0);
mips_jr (code, ins->sreg1);
mips_nop (code);
break;
- case CEE_SWITCH: {
+ case OP_SWITCH: {
int i;
max_len += 4 * GPOINTER_TO_INT (ins->klass);
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
break;
}
case OP_CEQ:
+ case OP_ICEQ:
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:
+ case OP_ICLT:
+ case OP_ICLT_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:
+ case OP_ICGT:
+ case OP_ICGT_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);
- break;
-
- case OP_COND_EXC_EQ:
- case OP_COND_EXC_GE:
- case OP_COND_EXC_GT:
- case OP_COND_EXC_LE:
- case OP_COND_EXC_LT:
- case OP_COND_EXC_NE_UN:
- case OP_COND_EXC_GE_UN:
- case OP_COND_EXC_GT_UN:
- case OP_COND_EXC_LE_UN:
- case OP_COND_EXC_LT_UN:
-
- case OP_COND_EXC_OV:
- case OP_COND_EXC_NO:
- case OP_COND_EXC_C:
- case OP_COND_EXC_NC:
-
- case OP_COND_EXC_IEQ:
- case OP_COND_EXC_IGE:
- case OP_COND_EXC_IGT:
- case OP_COND_EXC_ILE:
- case OP_COND_EXC_ILT:
- case OP_COND_EXC_INE_UN:
- case OP_COND_EXC_IGE_UN:
- case OP_COND_EXC_IGT_UN:
- case OP_COND_EXC_ILE_UN:
- case OP_COND_EXC_ILT_UN:
-
- case OP_COND_EXC_IOV:
- case OP_COND_EXC_INO:
- case OP_COND_EXC_IC:
- case OP_COND_EXC_INC:
- /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
- g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
- g_assert_not_reached ();
+ MIPS_MOVE (code, ins->dreg, mips_zero);
break;
case OP_MIPS_COND_EXC_EQ:
the tests. */
/* Remember, an unpatched branch to 0 branches to the delay slot */
- throw = (guint32 *)(void *)code;
switch (ins->opcode) {
case OP_MIPS_COND_EXC_EQ:
+ throw = (guint32 *)(void *)code;
mips_beq (code, ins->sreg1, ins->sreg2, 0);
mips_nop (code);
break;
+
case OP_MIPS_COND_EXC_NE_UN:
+ throw = (guint32 *)(void *)code;
mips_bne (code, ins->sreg1, ins->sreg2, 0);
mips_nop (code);
break;
+
+ case OP_MIPS_COND_EXC_LE_UN:
+ mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
+ throw = (guint32 *)(void *)code;
+ mips_blez (code, mips_at, 0);
+ mips_nop (code);
+ break;
+
+ case OP_MIPS_COND_EXC_GT:
+ mips_slt (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_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_bne (code, mips_at, mips_zero, 0);
+ 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));
cfg->bb_exit->max_offset += 24;
break;
}
- case CEE_BEQ:
- case CEE_BNE_UN:
- case CEE_BLT:
- case CEE_BLT_UN:
- case CEE_BGT:
- case CEE_BGT_UN:
- case CEE_BGE:
- case CEE_BGE_UN:
- case CEE_BLE:
- case CEE_BLE_UN:
- /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
- g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
- g_assert_not_reached ();
- break;
case OP_MIPS_BEQ:
case OP_MIPS_BNE:
case OP_MIPS_BGEZ:
/* 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);
- }
+#endif
+ mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
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 CEE_CONV_R_UN: {
+ case OP_ICONV_TO_R_UN: {
static const guint64 adjust_val = 0x41F0000000000000ULL;
/* convert unsigned int to double */
/* target is here */
break;
}
- case CEE_CONV_R4:
+ case OP_ICONV_TO_R4:
mips_mtc1 (code, mips_ftemp, ins->sreg1);
mips_cvtsw (code, ins->dreg, mips_ftemp);
mips_cvtds (code, ins->dreg, ins->dreg);
break;
- case CEE_CONV_R8:
+ case OP_ICONV_TO_R8:
mips_mtc1 (code, mips_ftemp, ins->sreg1);
mips_cvtdw (code, ins->dreg, mips_ftemp);
break;
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);
break;
- case OP_FBEQ:
+ case OP_MIPS_FBEQ:
mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbtrue (code, 0);
mips_nop (code);
break;
- case OP_FBNE_UN:
+ case OP_MIPS_FBNE:
mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbfalse (code, 0);
mips_nop (code);
break;
- case OP_FBLT:
+ case OP_MIPS_FBLT:
mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
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)
mips_fbtrue (code, 0);
mips_nop (code);
break;
- case OP_FBGT:
+ case OP_MIPS_FBGT:
mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbfalse (code, 0);
mips_nop (code);
break;
- case OP_FBGT_UN:
+ case OP_MIPS_FBGT_UN:
mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbfalse (code, 0);
mips_nop (code);
break;
- case OP_FBGE:
+ case OP_MIPS_FBGE:
mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbfalse (code, 0);
mips_nop (code);
break;
- case OP_FBGE_UN:
+ case OP_MIPS_FBGE_UN:
mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbfalse (code, 0);
mips_nop (code);
break;
- case OP_FBLE:
+ case OP_MIPS_FBLE:
mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
mips_fbtrue (code, 0);
mips_nop (code);
break;
- case OP_FBLE_UN:
+ case OP_MIPS_FBLE_UN:
mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
mips_nop (code);
if (ins->flags & MONO_INST_BRLABEL)
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_c1, ins->inst_p0);
+ mips_load (code, ins->dreg, 0x0f0f0f0f);
+ break;
+
+
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
g_assert_not_reached ();
last_ins = ins;
last_offset = offset;
-
- ins = ins->next;
}
cfg->code_len = code - cfg->native_code;
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:
patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
continue;
case MONO_PATCH_INFO_SWITCH: {
- /* jt is the inlined jump table, 7 or 9 instructions after ip
- * In the normal case we store the absolute addresses.
- * otherwise the displacements.
- */
- int i;
gpointer *table = (gpointer *)patch_info->data.table->table;
- gpointer *jt = ((gpointer*)(void *)ip) + 7;
- if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
- jt += 2;
+ int i;
+
+ patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
+
for (i = 0; i < patch_info->data.table->table_size; i++) {
- jt [i] = code + (int)table [i];
+ table [i] = (int)patch_info->data.table->table [i] + code;
}
continue;
}
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_addiu (code, mips_a1, mips_sp, 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_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 code;
}
+void
+mips_adjust_stackframe(MonoCompile *cfg)
+{
+ MonoBasicBlock *bb;
+ int delta, threshold, i;
+ MonoMethodSignature *sig;
+ int ra_offset;
+
+ if (cfg->stack_offset == cfg->arch.local_alloc_offset)
+ return;
+
+ /* adjust cfg->stack_offset for account for down-spilling */
+ 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);
+ delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
+ if (cfg->verbose_level > 2) {
+ g_print ("mips_adjust_stackframe:\n");
+ 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 - 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);
+ }
+
+ sig = mono_method_signature (cfg->method);
+ if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
+ cfg->vret_addr->inst_offset += delta;
+ }
+ for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+ MonoInst *inst = cfg->args [i];
+
+ inst->inst_offset += delta;
+ }
+
+ /*
+ * loads and stores based off the frame reg that (used to) lie
+ * above the spill var area need to be increased by 'delta'
+ * to make room for the spill vars.
+ */
+ /* Need to find loads and stores to adjust that
+ * are above where the spillvars were inserted, but
+ * which are not the spillvar references themselves.
+ *
+ * Idea - since all offsets from fp are positive, make
+ * spillvar offsets negative to begin with so we can spot
+ * them here.
+ */
+
+#if 1
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ int ins_cnt = 0;
+ MonoInst *ins;
+
+ if (cfg->verbose_level > 2) {
+ 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))
+ 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_print ("adj");
+ mono_print_ins_index (ins_cnt, ins);
+ }
+ }
+ else if (ins->inst_c0 < 0) {
+ ins->inst_c0 = - ins->inst_c0 - 4;
+ if (cfg->verbose_level > 2) {
+ g_print ("spill");
+ mono_print_ins_index (ins_cnt, ins);
+ }
+ }
+ 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;
+ }
+ }
+#endif
+}
+
/*
* Stack frame layout:
*
- * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET + cfg->param_area
+ * ------------------- sp + cfg->stack_usage + cfg->param_area
* param area incoming
* ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
* a0-a3 incoming
* locals
* ------------------- sp + cfg->param_area
* param area outgoing
- * ------------------- sp + 16
+ * ------------------- sp + MIPS_STACK_PARAM_OFFSET
* a0-a3 outgoing
* ------------------- sp
* red zone
cfg->code_size = 768 + sig->param_count * 20;
code = cfg->native_code = g_malloc (cfg->code_size);
- alloc_size = cfg->stack_offset;
- g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);
+ 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
+ }
- /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
- cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
+ /* adjust stackframe assignments for spillvars if needed */
+ mips_adjust_stackframe (cfg);
/* stack_offset should not be changed here. */
alloc_size = cfg->stack_offset;
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));
+ 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]));
+ MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
}
}
#endif
#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,
+ MIPS_SW (code, cfg->frame_reg, mips_sp,
lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
#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 */
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
ArgInfo *ainfo = &cinfo->ret;
- inst = cfg->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 {
mips_sw (code, ainfo->reg, mips_at, 0);
}
}
+ /* Keep this in sync with emit_load_volatile_arguments */
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
ArgInfo *ainfo = cinfo->args + i;
inst = cfg->args [pos];
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
/* Argument ends up on the stack */
if (ainfo->regtype == RegTypeGeneral) {
/* Incoming parameters should be above this frame */
- g_assert (inst->inst_offset >= alloc_size);
+ if (cfg->verbose_level > 2)
+ g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
+ /* g_assert (inst->inst_offset >= alloc_size); */
g_assert (mips_is_imm16 (inst->inst_offset));
switch (ainfo->size) {
case 1:
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));
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);
+ 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));
/* save method info */
mips_load_const (code, mips_at, 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));
+ 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);
int offset;
MonoMethod *method = cfg->method;
int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
- int save_offset = 16;
+ int save_offset = MIPS_STACK_PARAM_OFFSET;
- save_offset += 15;
- save_offset &= ~15;
+ g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
offset = code - cfg->native_code;
/* we need about 16 instructions */
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;
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);
+ 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);
+ mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
break;
case SAVE_STRUCT:
case SAVE_NONE:
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);
+ 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;
guint32 iregs_to_restore;
#if SAVE_FP_REGS
}
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 SAVE_ALL_REGS
iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
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);
+ MIPS_LW (code, i, mips_sp, pos);
+ pos += SIZEOF_REGISTER;
}
}
}
if (fregs_to_restore & (1 << i)) {
g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
mips_lwc1 (code, i, mips_sp, pos);
- pos += sizeof (gulong);
+ pos += FREG_SIZE
}
}
}
}
/* remove once throw_exception_by_name is eliminated */
+#if 0
static int
exception_id_by_name (const char *name)
{
g_error ("Unknown intrinsic exception %s\n", name);
return 0;
}
+#endif
void
mono_arch_emit_exceptions (MonoCompile *cfg)
/* add the this argument */
if (this_reg != -1) {
MonoInst *this;
- MONO_INST_NEW (cfg, this, OP_SETREG);
+ MONO_INST_NEW (cfg, this, OP_MOVE);
this->type = this_type;
this->sreg1 = this_reg;
- this->dreg = mono_regstate_next_int (cfg->rs);
+ this->dreg = mono_alloc_ireg (cfg);
mono_bblock_add_inst (cfg->cbb, this);
mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
}
if (vt_reg != -1) {
MonoInst *vtarg;
- MONO_INST_NEW (cfg, vtarg, OP_SETREG);
+ MONO_INST_NEW (cfg, vtarg, OP_MOVE);
vtarg->type = STACK_MP;
vtarg->sreg1 = vt_reg;
- vtarg->dreg = mono_regstate_next_int (cfg->rs);
+ vtarg->dreg = mono_alloc_ireg (cfg);
mono_bblock_add_inst (cfg->cbb, vtarg);
mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
}
{
MonoInst *ins = NULL;
- if (cmethod->klass == mono_defaults.thread_class &&
- strcmp (cmethod->name, "MemoryBarrier") == 0) {
- MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
- }
-#if 0
- if (cmethod->klass == mono_defaults.math_class) {
- if (strcmp (cmethod->name, "Sqrt") == 0) {
- MONO_INST_NEW (cfg, ins, OP_SQRT);
- ins->inst_i0 = args [0];
- }
- }
-#endif
return ins;
}
+MonoInst*
+mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ return NULL;
+}
+
gboolean
mono_arch_print_tree (MonoInst *tree, int arity)
{
return ins;
}
+gpointer
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ /* FIXME: implement */
+ g_assert_not_reached ();
+}
+
+#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
+
+/*
+ * LOCKING: called with the domain lock held
+ */
+gpointer
+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;
+
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ 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;
+ } else {
+ if (fail_tramp) {
+ item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
+ } else {
+ item->chunk_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;
+ imt_entries [item->check_target_idx]->compare_done = TRUE;
+ }
+ size += item->chunk_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);
+ }
+ start = code;
+ if (!fail_tramp)
+ ppc_load (code, ppc_r11, (guint32)(& (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);
+ }
+ 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);
+ } 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;
+ } 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_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);
+#if ENABLE_WRONG_METHOD_CHECK
+ ppc_patch (item->jmp_code, 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);
+ item->jmp_code = code;
+ ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
+ }
+ }
+ /* 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 (!fail_tramp)
+ mono_stats.imt_thunks_size += code - start;
+ g_assert (code - start <= size);
+ mono_arch_flush_icache (start, size);
+ return start;
+#endif
+}
+
+MonoMethod*
+mono_arch_find_imt_method (gpointer *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)
+{
+ NOT_IMPLEMENTED;
+ return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
+}