#include <sys/sysctl.h>
#endif
+/* From ir-emit.h */
+static inline guint32
+alloc_ireg (MonoCompile *cfg)
+{
+ return cfg->next_vreg ++;
+}
+
+static inline guint32
+alloc_lreg (MonoCompile *cfg)
+{
+#if SIZEOF_VOID_P == 8
+ return cfg->next_vreg ++;
+#else
+ /* Use a pair of consecutive vregs */
+ guint32 res = cfg->next_vreg;
+
+ cfg->next_vreg += 3;
+
+ return res;
+#endif
+}
+
+static inline guint32
+alloc_freg (MonoCompile *cfg)
+{
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* Allocate an lvreg so float ops can be decomposed into long ops */
+ return alloc_lreg (cfg);
+#else
+ /* Allocate these from the same pool as the int regs */
+ return cfg->next_vreg ++;
+#endif
+}
+
+static inline guint32
+alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
+{
+ switch (stack_type) {
+ case STACK_I4:
+ case STACK_PTR:
+ case STACK_MP:
+ case STACK_OBJ:
+ return alloc_ireg (cfg);
+ case STACK_R8:
+ return alloc_freg (cfg);
+ case STACK_I8:
+ return alloc_lreg (cfg);
+ case STACK_VTYPE:
+ return alloc_ireg (cfg);
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
+#else
+#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
+#endif
+
+#define NEW_VARLOADA(cfg,dest,var,vartype) do { \
+ MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
+ (dest)->inst_p0 = (var); \
+ (var)->flags |= MONO_INST_INDIRECT; \
+ (dest)->type = STACK_MP; \
+ (dest)->klass = (var)->klass; \
+ (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
+ if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
+ } while (0)
+
+#define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
+
#define FORCE_INDIR_CALL 1
enum {
for (k = 0; k < param_count; k++) {
if (csig->pinvoke)
- size = mono_type_native_stack_size (csig->params [k], &align);
+ size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
else
size = mini_type_stack_size (NULL, csig->params [k], &align);
}
gpointer
-mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
+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))
if (!cachelinesize) {
#ifdef __APPLE__
- int mib [3], len;
+ int mib [3];
+ size_t len;
mib [0] = CTL_HW;
mib [1] = HW_CACHELINE;
len = sizeof (cachelinesize);
- if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
+ if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
perror ("sysctl");
cachelinesize = 128;
} else {
asm ("isync");
}
+void
+mono_arch_flush_register_windows (void)
+{
+}
+
#ifdef __APPLE__
#define ALWAYS_ON_STACK(s) s
#define FP_ALSO_IN_REG(s) s
}
#if __APPLE__
-/* size == 4 is checked already */
static gboolean
-has_only_a_r4_field (MonoClass *klass)
+has_only_a_r48_field (MonoClass *klass)
{
gpointer iter;
MonoClassField *f;
+ gboolean have_field = FALSE;
iter = NULL;
while ((f = mono_class_get_fields (klass, &iter))) {
if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
- if (!f->type->byref && f->type->type == MONO_TYPE_R4)
- return TRUE;
- return FALSE;
+ if (have_field)
+ return FALSE;
+ if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
+ have_field = TRUE;
+ else
+ return FALSE;
}
}
- return FALSE;
+ return have_field;
}
#endif
}
DEBUG(printf("params: %d\n", sig->param_count));
for (i = 0; i < sig->param_count; ++i) {
- if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
/* Prevent implicit arguments and sig_cookie from
being passed in registers */
gr = PPC_LAST_ARG_REG + 1;
+ /* FIXME: don't we have to set fr, too? */
/* Emit the signature cookie just before the implicit arguments */
add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
}
else
size = mono_class_value_size (klass, NULL);
#if __APPLE__
- if (size == 4 && has_only_a_r4_field (klass)) {
- cinfo->args [n].size = 4;
+ if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
+ cinfo->args [n].size = size;
/* It was 7, now it is 8 in LinuxPPC */
if (fr <= PPC_LAST_FPARG_REG) {
cinfo->args [n].reg = fr;
fr ++;
FP_ALSO_IN_REG (gr ++);
- ALWAYS_ON_STACK (stack_size += 4);
+ if (size == 8)
+ FP_ALSO_IN_REG (gr ++);
+ ALWAYS_ON_STACK (stack_size += size);
} else {
cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
cinfo->args [n].regtype = RegTypeBase;
cinfo->args [n].reg = ppc_sp; /* in the caller*/
- stack_size += 4;
+ stack_size += 8;
}
n++;
break;
{
int align_size = size;
int nwords = 0;
+ int rest = PPC_LAST_ARG_REG - gr + 1;
+ int n_in_regs;
align_size += (sizeof (gpointer) - 1);
align_size &= ~(sizeof (gpointer) - 1);
nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
+ n_in_regs = rest >= nwords? nwords: rest;
cinfo->args [n].regtype = RegTypeStructByVal;
if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
cinfo->args [n].size = 0;
cinfo->args [n].vtsize = nwords;
} else {
- int rest = PPC_LAST_ARG_REG - 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 = gr;
- gr += n_in_regs;
}
+ gr += n_in_regs;
cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
/*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
stack_size += nwords * sizeof (gpointer);
}
}
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+ /* Prevent implicit arguments and sig_cookie from
+ being passed in registers */
+ gr = PPC_LAST_ARG_REG + 1;
+ /* Emit the signature cookie just before the implicit arguments */
+ add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
+ }
+
{
simpletype = mono_type_get_underlying_type (sig->ret)->type;
switch (simpletype) {
return cinfo;
}
+static void
+allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
+{
+#if !PPC_PASS_STRUCTS_BY_VALUE
+ MonoMethodSignature *sig = mono_method_signature (cfg->method);
+ int num_structs = 0;
+ int i;
+
+ if (!(cfg->flags & MONO_CFG_HAS_TAIL))
+ return;
+
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *type = mono_type_get_underlying_type (sig->params [i]);
+ if (type->type == MONO_TYPE_VALUETYPE)
+ num_structs++;
+ }
+
+ if (num_structs) {
+ cfg->tailcall_valuetype_addrs =
+ mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
+ for (i = 0; i < num_structs; ++i) {
+ cfg->tailcall_valuetype_addrs [i] =
+ mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
+ }
+ }
+#endif
+}
/*
* Set var information according to the calling convention. ppc version.
MonoInst *inst;
int i, offset, size, align, curinst;
int frame_reg = ppc_sp;
+ gint32 *offsets;
+ guint32 locals_stack_size, locals_stack_align;
+
+ allocate_tailcall_valuetype_addrs (m);
m->flags |= MONO_CFG_HAS_SPILLUP;
curinst = 0;
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
m->ret->opcode = OP_REGVAR;
- m->ret->inst_c0 = ppc_r3;
+ m->ret->inst_c0 = m->ret->dreg = ppc_r3;
} else {
- /* FIXME: handle long and FP values */
+ /* FIXME: handle long values? */
switch (mono_type_get_underlying_type (sig->ret)->type) {
case MONO_TYPE_VOID:
break;
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ m->ret->opcode = OP_REGVAR;
+ m->ret->inst_c0 = m->ret->dreg = ppc_f1;
+ break;
default:
m->ret->opcode = OP_REGVAR;
- m->ret->inst_c0 = ppc_r3;
+ m->ret->inst_c0 = m->ret->dreg = ppc_r3;
break;
}
}
}
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
- inst = m->ret;
offset += sizeof(gpointer) - 1;
offset &= ~(sizeof(gpointer) - 1);
- inst->inst_offset = offset;
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
+
+ if (m->new_ir) {
+ m->vret_addr->opcode = OP_REGOFFSET;
+ m->vret_addr->inst_basereg = frame_reg;
+ m->vret_addr->inst_offset = offset;
+
+ if (G_UNLIKELY (m->verbose_level > 1)) {
+ printf ("vret_addr =");
+ mono_print_ins (m->vret_addr);
+ }
+ } else {
+ inst = m->ret;
+ inst->inst_offset = offset;
+ inst->opcode = OP_REGOFFSET;
+ inst->inst_basereg = frame_reg;
+ }
+
offset += sizeof(gpointer);
if (sig->call_convention == MONO_CALL_VARARG)
m->sig_cookie += sizeof (gpointer);
}
- curinst = m->locals_start;
- for (i = curinst; i < m->num_varinfo; ++i) {
- inst = m->varinfo [i];
- if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
- continue;
-
- /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
- * pinvoke wrappers when they call functions returning structure */
- if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
- size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
- else
- size = mono_type_size (inst->inst_vtype, &align);
-
- offset += align - 1;
- offset &= ~(align - 1);
- inst->inst_offset = offset;
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
- offset += size;
- //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
+ offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
+ if (locals_stack_align) {
+ offset += (locals_stack_align - 1);
+ offset &= ~(locals_stack_align - 1);
}
+ for (i = m->locals_start; i < m->num_varinfo; i++) {
+ if (offsets [i] != -1) {
+ MonoInst *inst = m->varinfo [i];
+ inst->opcode = OP_REGOFFSET;
+ inst->inst_basereg = frame_reg;
+ inst->inst_offset = offset + offsets [i];
+ /*
+ g_print ("allocating local %d (%s) to %d\n",
+ i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
+ */
+ }
+ }
+ offset += locals_stack_size;
curinst = 0;
if (sig->hasthis) {
if (inst->opcode != OP_REGVAR) {
inst->opcode = OP_REGOFFSET;
inst->inst_basereg = frame_reg;
- size = mono_type_size (sig->params [i], &align);
+ if (sig->pinvoke) {
+ size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
+ inst->backend.is_pinvoke = 1;
+ } else {
+ size = mono_type_size (sig->params [i], &align);
+ }
offset += align - 1;
offset &= ~(align - 1);
inst->inst_offset = offset;
/* change sign? */
m->stack_offset = offset;
+ if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
+ CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
+
+ m->sig_cookie = cinfo->sig_cookie.offset;
+
+ g_free(cinfo);
+ }
+}
+
+void
+mono_arch_create_vars (MonoCompile *cfg)
+{
+ MonoMethodSignature *sig = mono_method_signature (cfg->method);
+
+ if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
+ cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
+ }
}
/* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
MONO_INST_NEW (cfg, arg, OP_OUTARG);
arg->inst_imm = cinfo->sig_cookie.offset;
arg->inst_left = sig_arg;
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+ arg->inst_call = call;
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
}
if (is_virtual && i == 0) {
/* the argument will be attached to the call instrucion */
arg->inst_left = in;
arg->inst_call = call;
arg->type = in->type;
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
if (ainfo->regtype == RegTypeGeneral) {
arg->backend.reg3 = ainfo->reg;
call->used_iregs |= 1 << ainfo->reg;
}
}
}
+ /*
+ * Reverse the call->out_args list.
+ */
+ {
+ MonoInst *prev = NULL, *list = call->out_args, *next;
+ while (list) {
+ next = list->next;
+ list->next = prev;
+ prev = list;
+ list = next;
+ }
+ call->out_args = prev;
+ }
+
call->stack_usage = cinfo->stack_usage;
cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
cfg->flags |= MONO_CFG_HAS_CALLS;
return call;
}
+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,
+ ppc_r1, 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;
+
+ sig = call->signature;
+ n = sig->param_count + sig->hasthis;
+
+ cinfo = calculate_sizes (sig, sig->pinvoke);
+
+ for (i = 0; i < n; ++i) {
+ 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 = mono_type_get_underlying_type (t);
+
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
+ emit_sig_cookie (cfg, call, cinfo);
+
+ in = call->args [i];
+
+ if (ainfo->regtype == RegTypeGeneral) {
+ 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 {
+ 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, ppc_r1, 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, ppc_r1, ainfo->offset, in->dreg);
+ else
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
+ } else {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, 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) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_FMOVE);
+ ins->dreg = dreg;
+ ins->sreg1 = in->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
+ 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);
+ }
+
+ call->stack_usage = cinfo->stack_usage;
+ cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
+ cfg->flags |= MONO_CFG_HAS_CALLS;
+
+ g_free (cinfo);
+}
+
+void
+mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
+{
+ MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
+ ArgInfo *ainfo = ins->inst_p1;
+ int ovf_size = ainfo->vtsize;
+ int doffset = ainfo->offset;
+ int i, soffset, dreg;
+
+ if (ainfo->regtype == RegTypeStructByVal) {
+ guint32 size = 0;
+ soffset = 0;
+#ifdef __APPLE__
+ /*
+ * Darwin pinvokes needs some special handling for 1
+ * and 2 byte arguments
+ */
+ g_assert (ins->klass);
+ if (call->signature->pinvoke)
+ size = mono_class_native_size (ins->klass, NULL);
+ if (size == 2 || size == 1) {
+ int tmpr = mono_alloc_ireg (cfg);
+ if (size == 1)
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
+ else
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
+ dreg = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
+ mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
+ } else
+#endif
+ 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 (gpointer);
+ }
+ if (ovf_size != 0)
+ mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, 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_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
+
+ if (ainfo->offset)
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, 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 = mono_type_get_underlying_type (mono_method_signature (method)->ret);
+
+ if (!ret->byref) {
+ 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;
+ }
+ if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
+ return;
+ }
+ }
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+}
+
+/* FIXME: this is just a useless hint: fix the interface to include the opcode */
+gboolean
+mono_arch_is_inst_imm (gint64 imm)
+{
+ return TRUE;
+}
+
/*
* Allow tracing to work with this interface (with an optional argument)
*/
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
code = cfg->native_code + offset;
}
-handle_enum:
+
switch (rtype) {
case MONO_TYPE_VOID:
/* special case string .ctor icall */
#define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
-static void
-peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
+void
+mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+}
+
+void
+mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
{
- MonoInst *ins, *n;
+ MonoInst *ins, *n, *last_ins = NULL;
- MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
- MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
+ MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
switch (ins->opcode) {
case OP_MUL_IMM:
/* remove unnecessary multiplication with 1 */
if (ins->dreg != ins->sreg1) {
ins->opcode = OP_MOVE;
} else {
- MONO_DEL_INS (ins);
+ MONO_DELETE_INS (bb, ins);
continue;
}
} else {
ins->inst_basereg == last_ins->inst_destbasereg &&
ins->inst_offset == last_ins->inst_offset) {
if (ins->dreg == last_ins->sreg1) {
- MONO_DEL_INS (ins);
+ 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) {
- MONO_DEL_INS (ins);
+ 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_MOVE:
ins->opcode = OP_MOVE;
/*
* OP_MOVE reg, reg
*/
if (ins->dreg == ins->sreg1) {
- MONO_DEL_INS (ins);
+ MONO_DELETE_INS (bb, ins);
continue;
}
/*
if (last_ins && last_ins->opcode == OP_MOVE &&
ins->sreg1 == last_ins->dreg &&
ins->dreg == last_ins->sreg1) {
- MONO_DEL_INS (ins);
+ MONO_DELETE_INS (bb, ins);
continue;
}
break;
}
+ last_ins = ins;
+ ins = ins->next;
+ }
+ bb->last_ins = last_ins;
+}
+
+void
+mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
+{
+ g_assert (cfg->new_ir);
+
+ switch (ins->opcode) {
+ case OP_ICONV_TO_R_UN: {
+ static const guint64 adjust_val = 0x4330000000000000ULL;
+ int msw_reg = mono_alloc_ireg (cfg);
+ int adj_reg = mono_alloc_freg (cfg);
+ int tmp_reg = mono_alloc_freg (cfg);
+ MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
+ MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
+ MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
+ ins->opcode = OP_NOP;
+ break;
+ }
+ case OP_ICONV_TO_R4:
+ case OP_ICONV_TO_R8: {
+ /* FIXME: change precision for CEE_CONV_R4 */
+ static const guint64 adjust_val = 0x4330000080000000ULL;
+ int msw_reg = mono_alloc_ireg (cfg);
+ int xored = mono_alloc_ireg (cfg);
+ int adj_reg = mono_alloc_freg (cfg);
+ int tmp_reg = mono_alloc_freg (cfg);
+ MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
+ MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
+ MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
+ if (ins->opcode == OP_ICONV_TO_R4)
+ MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
+ ins->opcode = OP_NOP;
+ break;
+ }
+ case OP_CKFINITE: {
+ int msw_reg = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
+ MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
+ ins->opcode = OP_NOP;
+ break;
+ }
}
}
PPC_BR_LT
};
-#define NEW_INS(cfg,ins,dest,op) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = (op); \
- MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
+#define NEW_INS(cfg,dest,op) do { \
+ MONO_INST_NEW((cfg), (dest), (op)); \
+ mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
} while (0)
static int
{
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_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:
case OP_STOREI4_MEMBASE_IMM:
return OP_STOREI4_MEMBASE_REG;
}
- g_assert_not_reached ();
+ return mono_op_imm_to_op (op);
}
+//#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
+
#define compare_opcode_is_unsigned(opcode) \
(((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
+ (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
- ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
+ ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
+ ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
/*
* 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;
+ MonoInst *ins, *next, *temp, *last_ins = NULL;
int imm;
/* setup the virtual reg allocator */
MONO_BB_FOR_EACH_INS (bb, ins) {
loop_start:
switch (ins->opcode) {
+ case OP_IDIV_UN_IMM:
+ case OP_IDIV_IMM:
+ case OP_IREM_IMM:
+ case OP_IREM_UN_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;
+ 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;
+ case OP_IREM:
+ case OP_IREM_UN: {
+ MonoInst *mul;
+ /* we change a rem dest, src1, src2 to
+ * div temp1, src1, src2
+ * mul temp2, temp1, src2
+ * sub dest, src1, temp2
+ */
+ NEW_INS (cfg, mul, OP_IMUL);
+ NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
+ temp->sreg1 = ins->sreg1;
+ temp->sreg2 = ins->sreg2;
+ temp->dreg = mono_regstate_next_int (cfg->rs);
+ mul->sreg1 = temp->dreg;
+ mul->sreg2 = ins->sreg2;
+ mul->dreg = mono_regstate_next_int (cfg->rs);
+ ins->opcode = OP_ISUB;
+ ins->sreg2 = mul->dreg;
+ break;
+ }
+ case OP_IADD_IMM:
case OP_ADD_IMM:
case OP_ADDCC_IMM:
if (!ppc_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
}
break;
+ case OP_ISUB_IMM:
case OP_SUB_IMM:
if (!ppc_is_imm16 (-ins->inst_imm)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
}
break;
+ case OP_IAND_IMM:
+ case OP_IOR_IMM:
+ case OP_IXOR_IMM:
case OP_AND_IMM:
case OP_OR_IMM:
case OP_XOR_IMM:
if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
}
break;
+ case OP_ISBB_IMM:
+ case OP_IADC_IMM:
case OP_SBB_IMM:
case OP_SUBCC_IMM:
case OP_ADC_IMM:
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
break;
case OP_COMPARE_IMM:
- next = mono_inst_list_next (&ins->node, &bb->ins_list);
+ case OP_ICOMPARE_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;
+ }
g_assert(next);
if (compare_opcode_is_unsigned (next->opcode)) {
if (!ppc_is_uimm16 (ins->inst_imm)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
temp->dreg = mono_regstate_next_int (cfg->rs);
ins->sreg2 = temp->dreg;
}
} else {
if (!ppc_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
temp->dreg = mono_regstate_next_int (cfg->rs);
ins->sreg2 = temp->dreg;
}
}
break;
+ case OP_IMUL_IMM:
case OP_MUL_IMM:
if (ins->inst_imm == 1) {
ins->opcode = OP_MOVE;
break;
}
if (!ppc_is_imm16 (ins->inst_imm)) {
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
}
break;
+ case OP_LOCALLOC_IMM:
+ 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 = OP_LOCALLOC;
+ break;
case OP_LOAD_MEMBASE:
case OP_LOADI4_MEMBASE:
case OP_LOADU4_MEMBASE:
*/
if (ppc_is_imm16 (ins->inst_offset))
break;
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_offset;
temp->dreg = mono_regstate_next_int (cfg->rs);
ins->sreg2 = temp->dreg;
case OP_STOREI1_MEMBASE_IMM:
case OP_STOREI2_MEMBASE_IMM:
case OP_STOREI4_MEMBASE_IMM:
- NEW_INS (cfg, ins, temp, OP_ICONST);
+ 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);
+ last_ins = temp;
goto loop_start; /* make it handle the possibly big ins->inst_offset */
case OP_R8CONST:
case OP_R4CONST:
- NEW_INS (cfg, ins, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_p0;
+ NEW_INS (cfg, temp, OP_ICONST);
+ temp->inst_c0 = (guint32)ins->inst_p0;
temp->dreg = mono_regstate_next_int (cfg->rs);
ins->inst_basereg = temp->dreg;
ins->inst_offset = 0;
ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
+ last_ins = temp;
/* make it handle the possibly big ins->inst_offset
* later optimize to use lis + load_membase
*/
goto loop_start;
}
+ last_ins = ins;
}
+ bb->last_ins = last_ins;
bb->max_vreg = cfg->rs->next_vreg;
}
-void
-mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- if (MONO_INST_LIST_EMPTY (&bb->ins_list))
- 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)
{
return code;
}
-static unsigned char*
-mono_emit_stack_alloc (guchar *code, MonoInst* tree)
-{
-#if 0
- int sreg = tree->sreg1;
- x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
- if (tree->flags & MONO_INST_INIT) {
- int offset = 0;
- if (tree->dreg != X86_EAX && sreg != X86_EAX) {
- x86_push_reg (code, X86_EAX);
- offset += 4;
- }
- if (tree->dreg != X86_ECX && sreg != X86_ECX) {
- x86_push_reg (code, X86_ECX);
- offset += 4;
- }
- if (tree->dreg != X86_EDI && sreg != X86_EDI) {
- x86_push_reg (code, X86_EDI);
- offset += 4;
- }
-
- x86_shift_reg_imm (code, X86_SHR, sreg, 2);
- if (sreg != X86_ECX)
- x86_mov_reg_reg (code, X86_ECX, sreg, 4);
- x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
-
- x86_lea_membase (code, X86_EDI, X86_ESP, offset);
- x86_cld (code);
- x86_prefix (code, X86_REP_PREFIX);
- x86_stosl (code);
-
- if (tree->dreg != X86_EDI && sreg != X86_EDI)
- x86_pop_reg (code, X86_EDI);
- if (tree->dreg != X86_ECX && sreg != X86_ECX)
- x86_pop_reg (code, X86_ECX);
- if (tree->dreg != X86_EAX && sreg != X86_EAX)
- x86_pop_reg (code, X86_EAX);
- }
-#endif
- return code;
-}
-
typedef struct {
guchar *code;
- guchar *target;
+ const guchar *target;
int absolute;
int found;
} PatchData;
guint32 *endthunks = (guint32*)(code + bsize);
guint32 load [2];
guchar *templ;
- int i, count = 0;
+ int count = 0;
int difflow, diffhigh;
/* always ensure a call from pdata->code can reach to the thunks without further thunks */
}
static void
-handle_thunk (int absolute, guchar *code, guchar *target) {
+handle_thunk (int absolute, guchar *code, const guchar *target) {
MonoDomain *domain = mono_domain_get ();
PatchData pdata;
}
void
-ppc_patch (guchar *code, guchar *target)
+ppc_patch (guchar *code, const guchar *target)
{
guint32 ins = *(guint32*)code;
guint32 prim = ins >> 26;
// g_print ("patched with 0x%08x\n", ins);
}
+static guint8*
+emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
+{
+ switch (ins->opcode) {
+ case OP_FCALL:
+ case OP_FCALL_REG:
+ case OP_FCALL_MEMBASE:
+ if (ins->dreg != ppc_f1)
+ ppc_fmr (code, ins->dreg, ppc_f1);
+ break;
+ }
+
+ 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;
+ guint32 i, pos;
+ int struct_index = 0;
+
+ /* FIXME: Generate intermediate code instead */
+
+ sig = mono_method_signature (method);
+
+ /* This is the opposite of the code in emit_prolog */
+
+ pos = 0;
+
+ cinfo = calculate_sizes (sig, sig->pinvoke);
+
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ ArgInfo *ainfo = &cinfo->ret;
+ inst = cfg->vret_addr;
+ g_assert (ppc_is_imm16 (inst->inst_offset));
+ ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ }
+ for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+ ArgInfo *ainfo = cinfo->args + i;
+ inst = cfg->args [pos];
+
+ g_assert (inst->opcode != OP_REGVAR);
+ g_assert (ppc_is_imm16 (inst->inst_offset));
+
+ switch (ainfo->regtype) {
+ case RegTypeGeneral:
+ switch (ainfo->size) {
+ case 1:
+ ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ break;
+ case 2:
+ ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ break;
+ default:
+ ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ break;
+ }
+ break;
+
+ case RegTypeFP:
+ switch (ainfo->size) {
+ case 4:
+ ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ break;
+ case 8:
+ ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ break;
+
+ case RegTypeBase:
+ /* FIXME: */
+ NOT_IMPLEMENTED;
+
+ case RegTypeStructByVal: {
+ guint32 size = 0;
+
+ /* FIXME: */
+ if (ainfo->vtsize)
+ NOT_IMPLEMENTED;
+#ifdef __APPLE__
+ /*
+ * Darwin pinvokes needs some special handling
+ * for 1 and 2 byte arguments
+ */
+ if (method->signature->pinvoke)
+ size = mono_class_native_size (inst->klass, NULL);
+ if (size == 1 || size == 2) {
+ /* FIXME: */
+ NOT_IMPLEMENTED;
+ } else
+#endif
+ for (i = 0; i < ainfo->size; ++i) {
+ ppc_lwz (code, ainfo->reg + i,
+ inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
+ }
+ break;
+ }
+
+ case RegTypeStructByAddr: {
+ MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
+
+ g_assert (ppc_is_imm16 (addr->inst_offset));
+ g_assert (!ainfo->offset);
+ ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
+
+ struct_index++;
+ break;
+ }
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ pos ++;
+ }
+
+ g_free (cinfo);
+
+ return code;
+}
+
void
mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
{
MonoCallInst *call;
guint offset;
guint8 *code = cfg->native_code + cfg->code_len;
+ MonoInst *last_ins = NULL;
guint last_offset = 0;
int max_len, cpos;
- if (cfg->opt & MONO_OPT_PEEPHOLE)
- peephole_pass (cfg, bb);
-
/* we don't align basic blocks of loops on ppc */
if (cfg->verbose_level > 2)
mono_debug_record_line_number (cfg, ins, offset);
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:
emit_tls_access (code, ins->dreg, ins->inst_offset);
break;
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_STOREI2_MEMBASE_REG:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_STORE_MEMBASE_REG:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_STOREI1_MEMINDEX:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
}
break;
case OP_LOADI1_MEMBASE:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
}
if (ins->opcode == OP_LOADI1_MEMBASE)
ppc_extsb (code, ins->dreg, ins->dreg);
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
}
break;
case OP_LOADI2_MEMBASE:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
}
break;
case OP_LOAD_MEMINDEX:
ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
ppc_extsb (code, ins->dreg, ins->dreg);
break;
- case CEE_CONV_I1:
+ case OP_ICONV_TO_I1:
ppc_extsb (code, ins->dreg, ins->sreg1);
break;
- case CEE_CONV_I2:
+ case OP_ICONV_TO_I2:
ppc_extsh (code, ins->dreg, ins->sreg1);
break;
- case CEE_CONV_U1:
+ case OP_ICONV_TO_U1:
ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
break;
- case CEE_CONV_U2:
+ case OP_ICONV_TO_U2:
ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
break;
case OP_COMPARE:
- next = mono_inst_list_next (&ins->node, &bb->ins_list);
+ case OP_ICOMPARE:
+ next = ins->next;
if (next && compare_opcode_is_unsigned (next->opcode))
ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
else
ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
break;
case OP_COMPARE_IMM:
- next = mono_inst_list_next (&ins->node, &bb->ins_list);
+ case OP_ICOMPARE_IMM:
+ next = ins->next;
if (next && compare_opcode_is_unsigned (next->opcode)) {
if (ppc_is_uimm16 (ins->inst_imm)) {
ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
ppc_break (code);
break;
case OP_ADDCC:
+ case OP_IADDCC:
ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
- case CEE_ADD:
+ case OP_IADD:
ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_ADC:
+ case OP_IADC:
ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_ADDCC_IMM:
}
break;
case OP_ADD_IMM:
+ case OP_IADD_IMM:
if (ppc_is_imm16 (ins->inst_imm)) {
ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
} else {
g_assert_not_reached ();
}
break;
- case CEE_ADD_OVF:
+ case OP_IADD_OVF:
/* check XER [0-3] (SO, OV, CA): we can't use mcrxr
*/
ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
break;
- case CEE_ADD_OVF_UN:
+ case OP_IADD_OVF_UN:
/* check XER [0-3] (SO, OV, CA): we can't use mcrxr
*/
ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
break;
- case CEE_SUB_OVF:
+ case OP_ISUB_OVF:
/* check XER [0-3] (SO, OV, CA): we can't use mcrxr
*/
ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
break;
- case CEE_SUB_OVF_UN:
+ case OP_ISUB_OVF_UN:
/* check XER [0-3] (SO, OV, CA): we can't use mcrxr
*/
ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
break;
case OP_SUBCC:
+ case OP_ISUBCC:
ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
break;
- case CEE_SUB:
+ case OP_ISUB:
ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
break;
case OP_SBB:
+ case OP_ISBB:
ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
break;
case OP_SUB_IMM:
+ case OP_ISUB_IMM:
// we add the negated value
if (ppc_is_imm16 (-ins->inst_imm))
ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
case OP_PPC_SUBFZE:
ppc_subfze (code, ins->dreg, ins->sreg1);
break;
- case CEE_AND:
+ case OP_IAND:
/* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
break;
case OP_AND_IMM:
+ case OP_IAND_IMM:
if (!(ins->inst_imm & 0xffff0000)) {
ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
} else if (!(ins->inst_imm & 0xffff)) {
g_assert_not_reached ();
}
break;
- case CEE_DIV: {
- guint32 *divisor_is_m1;
+ case OP_IDIV: {
+ guint8 *divisor_is_m1;
/* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
*/
ppc_cmpi (code, 0, 0, ins->sreg2, -1);
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
break;
}
- case CEE_DIV_UN:
+ case OP_IDIV_UN:
ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
ppc_mfspr (code, ppc_r0, ppc_xer);
ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
break;
case OP_DIV_IMM:
- case CEE_REM:
- case CEE_REM_UN:
+ case OP_IREM:
+ case OP_IREM_UN:
case OP_REM_IMM:
g_assert_not_reached ();
- case CEE_OR:
+ case OP_IOR:
ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_OR_IMM:
+ case OP_IOR_IMM:
if (!(ins->inst_imm & 0xffff0000)) {
ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
} else if (!(ins->inst_imm & 0xffff)) {
g_assert_not_reached ();
}
break;
- case CEE_XOR:
+ case OP_IXOR:
ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_IXOR_IMM:
case OP_XOR_IMM:
if (!(ins->inst_imm & 0xffff0000)) {
ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
g_assert_not_reached ();
}
break;
- case CEE_SHL:
+ case OP_ISHL:
ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
break;
case OP_SHL_IMM:
+ case OP_ISHL_IMM:
ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
break;
- case CEE_SHR:
+ case OP_ISHR:
ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_SHR_IMM:
+ case OP_ISHR_IMM:
ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
break;
case OP_SHR_UN_IMM:
+ case OP_ISHR_UN_IMM:
if (ins->inst_imm)
ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
else
ppc_mr (code, ins->dreg, ins->sreg1);
break;
- case CEE_SHR_UN:
+ case OP_ISHR_UN:
ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
- case CEE_NOT:
+ case OP_INOT:
ppc_not (code, ins->dreg, ins->sreg1);
break;
- case CEE_NEG:
+ case OP_INEG:
ppc_neg (code, ins->dreg, ins->sreg1);
break;
- case CEE_MUL:
+ case OP_IMUL:
ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
+ case OP_IMUL_IMM:
case OP_MUL_IMM:
if (ppc_is_imm16 (ins->inst_imm)) {
ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
g_assert_not_reached ();
}
break;
- case CEE_MUL_OVF:
+ case OP_IMUL_OVF:
/* we annot use mcrxr, since it's not implemented on some processors
* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
*/
ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
break;
- case CEE_MUL_OVF_UN:
+ case OP_IMUL_OVF_UN:
/* we first multiply to get the high word and compare to 0
* to set the flags, then the result is discarded and then
* we multiply to get the lower * bits result
ppc_lis (code, ins->dreg, 0);
ppc_ori (code, ins->dreg, ins->dreg, 0);
break;
- case CEE_CONV_I4:
- case CEE_CONV_U4:
+ case OP_ICONV_TO_I4:
+ case OP_ICONV_TO_U4:
case OP_MOVE:
ppc_mr (code, ins->dreg, ins->sreg1);
break;
}
ppc_mtlr (code, ppc_r0);
}
+
+ code = emit_load_volatile_arguments (cfg, code);
+
if (ppc_is_imm16 (cfg->stack_usage)) {
ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
} else {
case OP_FCALL:
case OP_LCALL:
case OP_VCALL:
+ case OP_VCALL2:
case OP_VOIDCALL:
case OP_CALL:
call = (MonoCallInst*)ins;
} else {
ppc_bl (code, 0);
}
+ /* FIXME: this should be handled somewhere else in the new jit */
+ code = emit_move_return_value (cfg, ins, code);
break;
case OP_FCALL_REG:
case OP_LCALL_REG:
case OP_VCALL_REG:
+ case OP_VCALL2_REG:
case OP_VOIDCALL_REG:
case OP_CALL_REG:
ppc_mtlr (code, ins->sreg1);
ppc_blrl (code);
+ /* FIXME: this should be handled somewhere else in the new jit */
+ code = emit_move_return_value (cfg, ins, code);
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:
ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
ppc_mtlr (code, ppc_r0);
ppc_blrl (code);
+ /* FIXME: this should be handled somewhere else in the new jit */
+ code = emit_move_return_value (cfg, ins, code);
break;
case OP_OUTARG:
g_assert_not_reached ();
break;
case OP_LOCALLOC: {
- guint32 * zero_loop_jump, * zero_loop_start;
+ guint8 * zero_loop_jump, * zero_loop_start;
/* keep alignment */
int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
int area_offset = alloca_waste;
}
break;
}
- case OP_START_HANDLER:
+ case OP_START_HANDLER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
ppc_mflr (code, ppc_r0);
- if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
- ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+ if (ppc_is_imm16 (spvar->inst_offset)) {
+ ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
} else {
- ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
- ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
+ ppc_load (code, ppc_r11, spvar->inst_offset);
+ ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
}
break;
- case OP_ENDFILTER:
+ }
+ case OP_ENDFILTER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
if (ins->sreg1 != ppc_r3)
ppc_mr (code, ppc_r3, ins->sreg1);
- if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
- ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+ if (ppc_is_imm16 (spvar->inst_offset)) {
+ ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
} else {
- ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
- ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
+ ppc_load (code, ppc_r11, spvar->inst_offset);
+ ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
}
ppc_mtlr (code, ppc_r0);
ppc_blr (code);
break;
- case OP_ENDFINALLY:
- ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
+ }
+ case OP_ENDFINALLY: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
ppc_mtlr (code, ppc_r0);
ppc_blr (code);
break;
+ }
case OP_CALL_HANDLER:
mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
ppc_bl (code, 0);
ppc_bcctr (code, PPC_BR_ALWAYS, 0);
break;
case OP_CEQ:
+ case OP_ICEQ:
ppc_li (code, ins->dreg, 0);
ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
ppc_li (code, ins->dreg, 1);
break;
case OP_CLT:
case OP_CLT_UN:
+ case OP_ICLT:
+ case OP_ICLT_UN:
ppc_li (code, ins->dreg, 1);
ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
ppc_li (code, ins->dreg, 0);
break;
case OP_CGT:
case OP_CGT_UN:
+ case OP_ICGT:
+ case OP_ICGT_UN:
ppc_li (code, ins->dreg, 1);
ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
ppc_li (code, ins->dreg, 0);
case OP_COND_EXC_LE_UN:
EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
break;
+ case OP_COND_EXC_IEQ:
+ case OP_COND_EXC_INE_UN:
+ case OP_COND_EXC_ILT:
+ case OP_COND_EXC_ILT_UN:
+ case OP_COND_EXC_IGT:
+ case OP_COND_EXC_IGT_UN:
+ case OP_COND_EXC_IGE:
+ case OP_COND_EXC_IGE_UN:
+ case OP_COND_EXC_ILE:
+ case OP_COND_EXC_ILE_UN:
+ EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
+ break;
case OP_COND_EXC_C:
/* check XER [0-3] (SO, OV, CA): we can't use mcrxr
*/
case OP_COND_EXC_NO:
g_assert_not_reached ();
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:
- EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
+ case OP_IBEQ:
+ case OP_IBNE_UN:
+ case OP_IBLT:
+ case OP_IBLT_UN:
+ case OP_IBGT:
+ case OP_IBGT_UN:
+ case OP_IBGE:
+ case OP_IBGE_UN:
+ case OP_IBLE:
+ case OP_IBLE_UN:
+ EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
break;
/* floating point opcodes */
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_LOADR8_MEMBASE:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_STORER4_MEMBASE_REG:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_LOADR4_MEMBASE:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
} else {
- g_assert_not_reached ();
+ ppc_load (code, ppc_r0, ins->inst_offset);
+ ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
}
break;
case OP_LOADR4_MEMINDEX:
g_assert_not_reached ();
/* Implemented as helper calls */
break;
+ case OP_LCONV_TO_OVF_I4_2:
case OP_LCONV_TO_OVF_I: {
- guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
+ guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
// Check if its negative
ppc_cmpi (code, 0, 0, ins->sreg1, 0);
negative_branch = code;
ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
break;
+ case OP_JUMP_TABLE:
+ mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+ ppc_load (code, ins->dreg, 0x0f0f0f0f);
+ break;
}
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
cpos += max_len;
+ last_ins = ins;
last_offset = offset;
}
for (patch_info = ji; patch_info; patch_info = patch_info->next) {
unsigned char *ip = patch_info->ip.i + code;
- const unsigned char *target;
+ unsigned char *target;
target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
CallInfo *cinfo;
int tracing = 0;
int lmf_offset = 0;
+ int tailcall_struct_index;
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
tracing = 1;
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
ArgInfo *ainfo = &cinfo->ret;
- inst = cfg->ret;
+
+ if (cfg->new_ir)
+ inst = cfg->vret_addr;
+ else
+ inst = cfg->ret;
+ g_assert (inst);
+
if (ppc_is_imm16 (inst->inst_offset)) {
ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
} else {
ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
}
}
+
+ tailcall_struct_index = 0;
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
ArgInfo *ainfo = cinfo->args + i;
inst = cfg->args [pos];
int size = 0;
g_assert (ppc_is_imm16 (inst->inst_offset));
g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
- if (mono_class_from_mono_type (inst->inst_vtype))
+ /* FIXME: what if there is no class? */
+ if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
-/*
-Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
-register. Should this case include linux/ppc?
-*/
#if __APPLE__
+ /*
+ * Darwin handles 1 and 2 byte
+ * structs specially by
+ * loading h/b into the arg
+ * register. Only done for
+ * pinvokes.
+ */
if (size == 2)
ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
else if (size == 1)
ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
- else
+ else
#endif
ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
soffset += sizeof (gpointer);
if (ainfo->vtsize) {
/* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
ppc_lwz (code, ppc_r11, 0, ppc_sp);
- /* FIXME: handle overrun! with struct sizes not multiple of 4 */
- code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
+ if ((size & 3) != 0) {
+ code = emit_memcpy (code, size - soffset,
+ inst->inst_basereg, doffset,
+ ppc_r11, ainfo->offset + soffset);
+ } else {
+ code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
+ inst->inst_basereg, doffset,
+ ppc_r11, ainfo->offset + soffset);
+ }
}
} else if (ainfo->regtype == RegTypeStructByAddr) {
/* if it was originally a RegTypeBase */
} else {
ppc_mr (code, ppc_r11, ainfo->reg);
}
+
+ if (cfg->tailcall_valuetype_addrs) {
+ MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
+
+ g_assert (ppc_is_imm16 (addr->inst_offset));
+ ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
+
+ tailcall_struct_index++;
+ }
+
g_assert (ppc_is_imm16 (inst->inst_offset));
code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
/*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
void
mono_arch_emit_epilog (MonoCompile *cfg)
{
- MonoJumpInfo *patch_info;
MonoMethod *method = cfg->method;
int pos, i;
int max_epilog_size = 16 + 20*4;
mono_arch_emit_exceptions (MonoCompile *cfg)
{
MonoJumpInfo *patch_info;
- int nthrows, i;
+ int i;
guint8 *code;
const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
- guint32 code_size;
- int exc_count = 0;
int max_epilog_size = 50;
/* count the number of exception infos */
} else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
max_epilog_size += 12;
else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
- MonoOvfJump *ovfj = patch_info->data.target;
+ MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
i = exception_id_by_name (ovfj->data.exception);
if (!exc_throw_found [i]) {
max_epilog_size += 24;
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_BB_OVF: {
- MonoOvfJump *ovfj = patch_info->data.target;
+ MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
unsigned char *ip = patch_info->ip.i + cfg->native_code;
/* patch the initial jump */
ppc_patch (ip, code);
break;
}
case MONO_PATCH_INFO_EXC_OVF: {
- MonoOvfJump *ovfj = patch_info->data.target;
+ MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
MonoJumpInfo *newji;
unsigned char *ip = patch_info->ip.i + cfg->native_code;
unsigned char *bcl = code;
} else {
ins = (guint32*) ((char*)ins + val);
}
- code = &val;
+ code = (guint32*)&val;
ppc_li (code, ppc_r0, 0x7FF2);
if (ins [1] == val) {
/* Darwin on G4, implement */
tls_mode = TLS_MODE_FAILED;
return;
} else {
- code = &val;
+ code = (guint32*)&val;
ppc_mfspr (code, ppc_r3, 104);
if (ins [1] != val) {
tls_mode = TLS_MODE_FAILED;
}
MonoObject*
-mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
{
- return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
+ return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
}
#endif
{
MonoInst *ins = NULL;
- if (cmethod->klass == mono_defaults.thread_class &&
- strcmp (cmethod->name, "MemoryBarrier") == 0) {
- MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
- }
/*if (cmethod->klass == mono_defaults.math_class) {
if (strcmp (cmethod->name, "Sqrt") == 0) {
MONO_INST_NEW (cfg, ins, OP_SQRT);
return ins;
}
+MonoInst*
+mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ /* FIXME: */
+ 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 ();
+}