#include "mini-ppc.h"
#include "inssel.h"
-#include "cpu-g4.h"
+#include "cpu-ppc.h"
#include "trace.h"
#ifdef __APPLE__
#include <sys/sysctl.h>
TLS_MODE_DARWIN_G5
};
+/* 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;
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 (NULL, csig->params [k], &align);
/* ignore alignment for now */
align = 1;
return frame_size;
}
+gpointer
+mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
+{
+ char *o = NULL;
+ int reg, offset = 0;
+ guint32* code = (guint32*)code_ptr;
+
+ *displacement = 0;
+
+ /* This is the 'blrl' instruction */
+ --code;
+
+ /* Sanity check: instruction must be 'blrl' */
+ if (*code != 0x4e800021)
+ return NULL;
+
+ /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
+ if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
+ return NULL;
+ }
+
+ /* OK, we're now at the 'blrl' instruction. Now walk backwards
+ till we get to a 'mtlr rA' */
+ for (; --code;) {
+ if((*code & 0x7c0803a6) == 0x7c0803a6) {
+ gint16 soff;
+ /* Here we are: we reached the 'mtlr rA'.
+ Extract the register from the instruction */
+ reg = (*code & 0x03e00000) >> 21;
+ --code;
+ /* ok, this is a lwz reg, offset (vtreg)
+ * it is emitted with:
+ * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
+ */
+ soff = (*code & 0xffff);
+ offset = soff;
+ reg = (*code >> 16) & 0x1f;
+ g_assert (reg != ppc_r1);
+ /*g_print ("patching reg is %d\n", reg);*/
+ if (reg >= 13) {
+ MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
+ /* saved in the MonoLMF structure */
+ o = (gpointer)lmf->iregs [reg - 13];
+ } else {
+ o = regs [reg];
+ }
+ break;
+ }
+ }
+ *displacement = offset;
+ return o;
+}
+
+gpointer*
+mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
+{
+ gpointer vt;
+ int displacement;
+ vt = mono_arch_get_vcall_slot (code, regs, &displacement);
+ if (!vt)
+ return NULL;
+ return (gpointer*)((char*)vt + displacement);
+}
+
+#define MAX_ARCH_DELEGATE_PARAMS 7
+
+gpointer
+mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
+{
+ guint8 *code, *start;
+
+ /* FIXME: Support more cases */
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ return NULL;
+
+ if (has_target) {
+ static guint8* cached = NULL;
+ mono_mini_arch_lock ();
+ if (cached) {
+ mono_mini_arch_unlock ();
+ return cached;
+ }
+
+ start = code = mono_global_codeman_reserve (16);
+
+ /* Replace the this argument with the target */
+ ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
+ ppc_mtctr (code, ppc_r0);
+ ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
+ ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+ g_assert ((code - start) <= 16);
+
+ mono_arch_flush_icache (start, 16);
+ cached = start;
+ mono_mini_arch_unlock ();
+ return cached;
+ } else {
+ static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
+ int size, i;
+
+ if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
+ return NULL;
+ for (i = 0; i < sig->param_count; ++i)
+ if (!mono_is_regsize_var (sig->params [i]))
+ return NULL;
+
+ mono_mini_arch_lock ();
+ code = cache [sig->param_count];
+ if (code) {
+ mono_mini_arch_unlock ();
+ return code;
+ }
+
+ size = 12 + sig->param_count * 4;
+ start = code = mono_global_codeman_reserve (size);
+
+ ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
+ ppc_mtctr (code, ppc_r0);
+ /* slide down the arguments */
+ for (i = 0; i < sig->param_count; ++i) {
+ ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
+ }
+ ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+ g_assert ((code - start) <= size);
+
+ mono_arch_flush_icache (start, size);
+ cache [sig->param_count] = start;
+ mono_mini_arch_unlock ();
+ return start;
+ }
+ return NULL;
+}
+
+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 [ppc_r4];
+ return (gpointer)regs [ppc_r3];
+}
+
/*
* 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);
}
/*
asm ("isync");
}
-#define NOT_IMPLEMENTED(x) \
- g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
-
#ifdef __APPLE__
#define ALWAYS_ON_STACK(s) s
#define FP_ALSO_IN_REG(s) s
}
+void
+mono_arch_create_vars (MonoCompile *cfg)
+{
+}
+
/* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
* currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
*/
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;
arg->inst_left = in;
arg->inst_call = call;
arg->type = in->type;
- /* prepend, we'll need to reverse them later */
+ /* prepend, so they get reversed */
arg->next = call->out_args;
call->out_args = arg;
if (ainfo->regtype == RegTypeGeneral) {
}
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;
}
+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->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+ /* FIXME: */
+ NOT_IMPLEMENTED;
+ }
+
+ 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, 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 + 1, 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) {
+ if (ainfo->offset) {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
+ } 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 == 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) {
+ MONO_INST_NEW (cfg, ins, OP_FMOVE);
+ ins->dreg = mono_alloc_freg (cfg);
+ ins->sreg1 = in->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
+ cfg->flags |= MONO_CFG_HAS_FPOUT;
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+
+ 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;
+
+ /* FIXME: handle darwin's 1/2 byte structs */
+ 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 (gpointer);
+ }
+ //g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
+ if (ovf_size != 0)
+ mini_emit_memcpy2 (cfg, ppc_r1, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
+}
+
+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)
*/
#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)
{
- MonoInst *ins, *last_ins = NULL;
- ins = bb->code;
+}
- while (ins) {
+void
+mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins, *n, *last_ins = NULL;
+ 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 {
- last_ins->next = ins->next;
- ins = ins->next;
+ 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) {
- 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_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;
}
+void
+mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
+{
+ switch (ins->opcode) {
+ case OP_ICONV_TO_R4: {
+ /* FIXME: change precision for CEE_CONV_R4 */
+ static const guint64 adjust_val = 0x4330000080000000ULL;
+ int msw_reg = mono_regstate_next_int (cfg->rs);
+ int xored = mono_regstate_next_int (cfg->rs);
+ int adj_reg = mono_regstate_next_float (cfg->rs);
+ int tmp_reg = mono_regstate_next_float (cfg->rs);
+ 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, &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;
+ }
+ }
+}
+
/*
* the branch_b0_table should maintain the order of these
* opcodes.
PPC_BR_LT
};
-static void
-insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
-{
- if (ins == NULL) {
- ins = bb->code;
- bb->code = to_insert;
- to_insert->next = ins;
- } else {
- to_insert->next = ins->next;
- ins->next = to_insert;
- }
-}
-
-#define NEW_INS(cfg,dest,op) do { \
+#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)); \
+ 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, *last_ins = NULL;
if (bb->max_vreg > cfg->rs->next_vreg)
cfg->rs->next_vreg = bb->max_vreg;
- ins = bb->code;
- while (ins) {
+ 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, 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, temp, OP_ICONST);
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:
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:
ins->opcode = map_to_reg_reg_op (ins->opcode);
break;
case OP_COMPARE_IMM:
- if (compare_opcode_is_unsigned (ins->next->opcode)) {
+ case OP_ICOMPARE_IMM:
+ next = ins->next;
+ g_assert(next);
+ if (compare_opcode_is_unsigned (next->opcode)) {
if (!ppc_is_uimm16 (ins->inst_imm)) {
NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
}
}
break;
+ case OP_IMUL_IMM:
case OP_MUL_IMM:
if (ins->inst_imm == 1) {
ins->opcode = OP_MOVE;
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:
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, temp, OP_ICONST);
+ temp->inst_c0 = 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;
- ins = ins->next;
}
bb->last_ins = last_ins;
bb->max_vreg = cfg->rs->next_vreg;
}
-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)
{
// 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;
+}
+
void
mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
{
- MonoInst *ins;
+ MonoInst *ins, *next;
MonoCallInst *call;
guint offset;
guint8 *code = cfg->native_code + cfg->code_len;
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)
//x86_inc_mem (code, &cov->data [bb->dfn].count);
}
- 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);
switch (ins->opcode) {
+ 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;
case OP_STOREI4_MEMINDEX:
ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
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);
- break;
case OP_LOADU4_MEM:
g_assert_not_reached ();
break;
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:
- if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
+ 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:
- if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
+ 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));
} else {
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: {
+ case OP_IDIV: {
guint32 *divisor_is_m1;
/* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
*/
ppc_cmpi (code, 0, 0, ins->sreg2, -1);
divisor_is_m1 = code;
ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
- ppc_lis (code, ppc_r11, 0x8000);
- ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
+ ppc_lis (code, ppc_r0, 0x8000);
+ ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
ppc_patch (divisor_is_m1, code);
/* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
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:
- g_assert_not_reached ();
-#if 0
- ppc_load (code, ppc_r11, ins->inst_imm);
- ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
- ppc_mfspr (code, ppc_r0, ppc_xer);
- ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
- /* FIXME: use OverflowException for 0x80000000/-1 */
- EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
- break;
-#endif
- case CEE_REM: {
- guint32 *divisor_is_m1;
- ppc_cmpi (code, 0, 0, ins->sreg2, -1);
- divisor_is_m1 = code;
- ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
- ppc_lis (code, ppc_r11, 0x8000);
- ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
- EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
- ppc_patch (divisor_is_m1, code);
- ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
- ppc_mfspr (code, ppc_r0, ppc_xer);
- ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
- /* FIXME: use OverflowException for 0x80000000/-1 */
- EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
- ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
- ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
- break;
- }
- case CEE_REM_UN:
- ppc_divwuod (code, ppc_r11, 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");
- ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
- ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
- break;
+ 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_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_ICONST:
- case OP_SETREGIMM:
ppc_load (code, ins->dreg, ins->inst_c0);
break;
case OP_AOTCONST:
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:
- case OP_SETREG:
ppc_mr (code, ins->dreg, ins->sreg1);
break;
case OP_SETLRET: {
ppc_mr (code, ppc_r4, saved);
break;
}
- case OP_SETFREG:
case OP_FMOVE:
ppc_fmr (code, ins->dreg, ins->sreg1);
break;
* Keep in sync with mono_arch_emit_epilog
*/
g_assert (!cfg->method->save_lmf);
+ /*
+ * Note: we can use ppc_r11 here because it is dead anyway:
+ * we're leaving the method.
+ */
if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
break;
case OP_ARGLIST: {
if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
- ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
+ ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
} else {
- ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
- ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
+ ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
+ ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
}
- ppc_stw (code, ppc_r11, 0, ins->sreg1);
+ ppc_stw (code, ppc_r0, 0, ins->sreg1);
break;
}
case OP_FCALL:
case OP_LCALL:
case OP_VCALL:
+ case OP_VCALL2:
case OP_VOIDCALL:
- case CEE_CALL:
+ case OP_CALL:
call = (MonoCallInst*)ins;
if (ins->flags & MONO_INST_HAS_METHOD)
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
} 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 ();
ppc_addi (code, ins->dreg, ppc_sp, area_offset);
break;
}
- case CEE_RET:
- ppc_blr (code);
- break;
case OP_THROW: {
//ppc_break (code);
ppc_mr (code, ppc_r3, ins->sreg1);
}
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);
ins->inst_c0 = code - cfg->native_code;
break;
case OP_BR:
- //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
- //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
- //break;
if (ins->flags & MONO_INST_BRLABEL) {
/*if (ins->inst_i0->inst_c0) {
ppc_b (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 */
case OP_R8CONST:
- ppc_load (code, ppc_r11, ins->inst_p0);
- ppc_lfd (code, ins->dreg, 0, ppc_r11);
- break;
case OP_R4CONST:
- ppc_load (code, ppc_r11, ins->inst_p0);
- ppc_lfs (code, ins->dreg, 0, ppc_r11);
- break;
+ g_assert_not_reached ();
case OP_STORER8_MEMBASE_REG:
if (ppc_is_imm16 (ins->inst_offset)) {
ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
case OP_STORER8_MEMINDEX:
ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
break;
- case CEE_CONV_R_UN: {
- static const guint64 adjust_val = 0x4330000000000000ULL;
- ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
- ppc_stw (code, ppc_r0, -8, ppc_sp);
- ppc_stw (code, ins->sreg1, -4, ppc_sp);
- ppc_load (code, ppc_r11, &adjust_val);
- ppc_lfd (code, ins->dreg, -8, ppc_sp);
- ppc_lfd (code, ppc_f0, 0, ppc_r11);
- ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
- break;
- }
+ case CEE_CONV_R_UN:
case CEE_CONV_R4: /* FIXME: change precision */
- case CEE_CONV_R8: {
- static const guint64 adjust_val = 0x4330000080000000ULL;
- // addis is special for ppc_r0
- ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
- ppc_stw (code, ppc_r0, -8, ppc_sp);
- ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
- ppc_stw (code, ppc_r11, -4, ppc_sp);
- ppc_lfd (code, ins->dreg, -8, ppc_sp);
- ppc_load (code, ppc_r11, &adjust_val);
- ppc_lfd (code, ppc_f0, 0, ppc_r11);
- ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
- break;
- }
+ case CEE_CONV_R8:
+ g_assert_not_reached ();
case OP_FCONV_TO_I1:
code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
break;
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;
// Check if its negative
case OP_FBLE_UN:
EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
break;
- case OP_CKFINITE: {
- 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);
+ case OP_CKFINITE:
+ g_assert_not_reached ();
+ case OP_CHECK_FINITE: {
+ ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
+ ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
+ 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__);
last_ins = ins;
last_offset = offset;
-
- ins = ins->next;
}
cfg->code_len = code - cfg->native_code;
*/
max_offset = 0;
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- MonoInst *ins = bb->code;
+ MonoInst *ins;
bb->max_offset = max_offset;
if (cfg->prof_options & MONO_PROFILE_COVERAGE)
max_offset += 6;
- while (ins) {
+ MONO_BB_FOR_EACH_INS (bb, ins)
max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
- ins = ins->next;
- }
}
/* load arguments allocated to register from the stack */
/* 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);
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);
}
}
+#ifdef MONO_ARCH_HAVE_IMT
+
+#define CMP_SIZE 12
+#define BR_SIZE 4
+#define JUMP_IMM_SIZE 12
+#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)
+{
+ 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;
+ item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
+ } 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;
+ }
+ /* the initial load of the vtable address */
+ size += 8;
+ code = mono_code_manager_reserve (domain->code_mp, size);
+ start = code;
+ 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->method);
+ 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_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
+ ppc_mtctr (code, ppc_r0);
+ ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+ } else {
+ /* enable the commented code to assert on wrong method */
+#if ENABLE_WRONG_METHOD_CHECK
+ ppc_load (code, ppc_r0, (guint32)item->method);
+ 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->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->method);
+ 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);
+ }
+ }
+ }
+
+ mono_stats.imt_thunks_size += code - start;
+ g_assert (code - start <= size);
+ mono_arch_flush_icache (start, size);
+ return start;
+}
+
+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
+
MonoInst*
mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
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 ();
+}