guint32 reg_usage;
guint32 freg_usage;
gboolean need_stack_align;
+ gboolean vtype_retaddr;
+ /* The index of the vret arg in the argument list */
+ int vret_arg_index;
ArgInfo ret;
ArgInfo sig_cookie;
ArgInfo args [1];
static CallInfo*
get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
{
- guint32 i, gr, fr;
+ guint32 i, gr, fr, pstart;
MonoType *ret_type;
int n = sig->hasthis + sig->param_count;
guint32 stack_size = 0;
cinfo->ret.reg = 8;
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
+ if (!mono_type_generic_inst_is_valuetype (ret_type)) {
cinfo->ret.storage = ArgInIReg;
cinfo->ret.reg = IA64_R8;
break;
cinfo->ret.storage = ArgInIReg;
} else {
add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
- if (cinfo->ret.storage == ArgOnStack)
+ if (cinfo->ret.storage == ArgOnStack) {
/* The caller passes the address where the value is stored */
- add_general (&gr, &stack_size, &cinfo->ret);
- if (cinfo->ret.storage == ArgInIReg)
- cinfo->ret.storage = ArgValuetypeAddrInIReg;
+ cinfo->vtype_retaddr = TRUE;
+ }
}
break;
}
}
}
- /* this */
- if (sig->hasthis)
- add_general (&gr, &stack_size, cinfo->args + 0);
+ pstart = 0;
+ /*
+ * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
+ * the first argument, allowing 'this' to be always passed in the first arg reg.
+ * Also do this if the first argument is a reference type, since virtual calls
+ * are sometimes made using calli without sig->hasthis set, like in the delegate
+ * invoke wrappers.
+ */
+ if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
+ if (sig->hasthis) {
+ add_general (&gr, &stack_size, cinfo->args + 0);
+ } else {
+ add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
+ pstart = 1;
+ }
+ add_general (&gr, &stack_size, &cinfo->ret);
+ if (cinfo->ret.storage == ArgInIReg)
+ cinfo->ret.storage = ArgValuetypeAddrInIReg;
+ cinfo->vret_arg_index = 1;
+ } else {
+ /* this */
+ if (sig->hasthis)
+ add_general (&gr, &stack_size, cinfo->args + 0);
+
+ if (cinfo->vtype_retaddr) {
+ add_general (&gr, &stack_size, &cinfo->ret);
+ if (cinfo->ret.storage == ArgInIReg)
+ cinfo->ret.storage = ArgValuetypeAddrInIReg;
+ }
+ }
if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
gr = PARAM_REGS;
add_general (&gr, &stack_size, &cinfo->sig_cookie);
}
- for (i = 0; i < sig->param_count; ++i) {
+ for (i = pstart; i < sig->param_count; ++i) {
ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
MonoType *ptype;
add_general (&gr, &stack_size, ainfo);
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+ if (!mono_type_generic_inst_is_valuetype (ptype)) {
add_general (&gr, &stack_size, ainfo);
break;
}
* This function returns the optimizations supported on this cpu.
*/
guint32
-mono_arch_cpu_optimizazions (guint32 *exclude_mask)
+mono_arch_cpu_optimizations (guint32 *exclude_mask)
{
*exclude_mask = 0;
return 0;
}
+/*
+ * This function test for all SIMD functions supported.
+ *
+ * Returns a bitmask corresponding to all supported versions.
+ *
+ */
+guint32
+mono_arch_cpu_enumerate_simd_versions (void)
+{
+ /* SIMD is currently unimplemented */
+ return 0;
+}
+
GList *
mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
{
MonoMethodHeader *header;
CallInfo *cinfo;
- header = mono_method_get_header (cfg->method);
+ header = cfg->header;
sig = mono_method_signature (cfg->method);
cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
- header = mono_method_get_header (cfg->method);
+ header = cfg->header;
/* Some registers are reserved for use by the prolog/epilog */
reserved_regs = header->num_clauses ? 4 : 3;
gint32 *offsets;
CallInfo *cinfo;
- header = mono_method_get_header (cfg->method);
+ header = cfg->header;
sig = mono_method_signature (cfg->method);
}
/* Allocate locals */
- offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
+ offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
if (locals_stack_align) {
offset = ALIGN_TO (offset, locals_stack_align);
}
if (MONO_IS_COND_BRANCH_OP (next)) {
next->opcode = OP_IA64_BR_COND;
- if (! (next->flags & MONO_INST_BRLABEL))
- next->inst_target_bb = next->inst_true_bb;
+ next->inst_target_bb = next->inst_true_bb;
} else if (MONO_IS_COND_EXC (next)) {
next->opcode = OP_IA64_COND_EXC;
} else if (MONO_IS_SETCC (next)) {
if (MONO_IS_COND_BRANCH_OP (next)) {
next->opcode = OP_IA64_BR_COND;
- if (! (next->flags & MONO_INST_BRLABEL))
- next->inst_target_bb = next->inst_true_bb;
+ next->inst_target_bb = next->inst_true_bb;
} else if (MONO_IS_COND_EXC (next)) {
next->opcode = OP_IA64_COND_EXC;
} else if (MONO_IS_SETCC (next)) {
cfg->code_size *= 2;
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
code_start = cfg->native_code + offset;
- mono_jit_stats.code_reallocs++;
+ cfg->stat_code_reallocs++;
ia64_codegen_init (code, code_start);
}
int pred = 0;
if (ins->opcode == OP_IA64_BR_COND)
pred = 6;
- if (ins->flags & MONO_INST_BRLABEL) {
- if (ins->inst_i0->inst_c0) {
- NOT_IMPLEMENTED;
- } else {
- add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
- ia64_br_cond_pred (code, pred, 0);
- }
- } else {
- if (ins->inst_target_bb->native_offset) {
- guint8 *pos = code.buf + code.nins;
+ if (ins->inst_target_bb->native_offset) {
+ guint8 *pos = code.buf + code.nins;
- ia64_br_cond_pred (code, pred, 0);
- ia64_begin_bundle (code);
- ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
- } else {
- add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
- ia64_br_cond_pred (code, pred, 0);
- }
- }
+ ia64_br_cond_pred (code, pred, 0);
+ ia64_begin_bundle (code);
+ ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
+ } else {
+ add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
+ ia64_br_cond_pred (code, pred, 0);
+ }
break;
}
case OP_LABEL:
ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_ISHR:
+ ia64_sxt4 (code, GP_SCRATCH_REG, ins->sreg1);
+ ia64_shr (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
+ break;
case OP_LSHR:
ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
case OP_SHR_IMM:
- case OP_ISHR_IMM:
case OP_LSHR_IMM:
ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
break;
+ case OP_ISHR_IMM:
+ g_assert (ins->inst_imm <= 64);
+ ia64_extr (code, ins->dreg, ins->sreg1, ins->inst_imm, 32 - ins->inst_imm);
+ break;
case OP_ISHR_UN_IMM:
ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
/* Calls */
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
- ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
+ /* Can't use ld8 as this could be a vtype address */
+ ia64_ld1 (code, GP_SCRATCH_REG, ins->sreg1);
break;
case OP_ARGLIST:
ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
int out_reg;
/*
- * mono_arch_find_this_arg () needs to find the this argument in a global
+ * mono_arch_get_this_arg_from_call () needs to find the this argument in a global
* register.
*/
cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
out_reg = cfg->arch.reg_out0;
- if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
- out_reg ++;
ia64_mov (code, IA64_R10, out_reg);
/* Indirect call */
CallInfo *cinfo;
int out_reg;
- /*
- * There are no membase instructions on ia64, but we can't
- * lower this since get_vcall_slot_addr () needs to decode it.
- */
-
- /* Keep this in synch with get_vcall_slot_addr */
ia64_mov (code, IA64_R11, ins->sreg1);
if (ia64_is_imm14 (ins->inst_offset))
ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
*/
cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
out_reg = cfg->arch.reg_out0;
- if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
- out_reg ++;
ia64_mov (code, IA64_R10, out_reg);
- ia64_begin_bundle (code);
- ia64_codegen_set_one_ins_per_bundle (code, TRUE);
-
ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
- /*
- * This nop will tell get_vcall_slot_addr that this is a virtual
- * call.
- */
- ia64_nop_i (code, 0x12345);
-
ia64_br_call_reg (code, IA64_B0, IA64_B6);
- ia64_codegen_set_one_ins_per_bundle (code, FALSE);
-
code = emit_move_return_value (cfg, ins, code);
break;
}
ia64_movl (code, GP_SCRATCH_REG2, 0);
ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
ia64_br_cond_reg (code, IA64_B6);
+ // FIXME:
+ //mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
ia64_codegen_set_one_ins_per_bundle (code, FALSE);
break;
case OP_START_HANDLER: {
}
void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
{
MonoJumpInfo *patch_info;
cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
- cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
+ cfg->code_size = MAX (cfg->header->code_size * 4, 512);
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
cfg->code_size += 1024;
while (cfg->code_len + max_epilog_size > cfg->code_size) {
cfg->code_size *= 2;
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
- mono_jit_stats.code_reallocs++;
+ cfg->stat_code_reallocs++;
}
/* FIXME: Emit unwind info */
while (cfg->code_len + code_size > (cfg->code_size - 16)) {
cfg->code_size *= 2;
cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
- mono_jit_stats.code_reallocs++;
+ cfg->stat_code_reallocs++;
}
ia64_codegen_init (code, cfg->native_code + cfg->code_len);
}
void*
-mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
+mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
{
Ia64CodegenState code;
CallInfo *cinfo = NULL;
return 0;
}
-gpointer
-mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
-{
- guint8 *bundle2 = code - 48;
- guint8 *bundle3 = code - 32;
- guint8 *bundle4 = code - 16;
- guint64 ins21 = ia64_bundle_ins1 (bundle2);
- guint64 ins22 = ia64_bundle_ins2 (bundle2);
- guint64 ins23 = ia64_bundle_ins3 (bundle2);
- guint64 ins31 = ia64_bundle_ins1 (bundle3);
- guint64 ins32 = ia64_bundle_ins2 (bundle3);
- guint64 ins33 = ia64_bundle_ins3 (bundle3);
- guint64 ins41 = ia64_bundle_ins1 (bundle4);
- guint64 ins42 = ia64_bundle_ins2 (bundle4);
- guint64 ins43 = ia64_bundle_ins3 (bundle4);
-
- /*
- * Virtual calls are made with:
- *
- * [MII] ld8 r31=[r8]
- * nop.i 0x0
- * nop.i 0x0;;
- * [MII] nop.m 0x0
- * mov.sptk b6=r31,0x2000000000f32a80
- * nop.i 0x0
- * [MII] nop.m 0x0
- * nop.i 0x123456
- * nop.i 0x0
- * [MIB] nop.m 0x0
- * nop.i 0x0
- * br.call.sptk.few b0=b6;;
- */
-
- if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
- (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
- (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
- (ins31 == IA64_NOP_M) &&
- (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
- (ins33 == IA64_NOP_I) &&
- (ins41 == IA64_NOP_M) &&
- (ins42 == IA64_NOP_I) &&
- (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
- ((ins32 >> 6) & 0xfffff) == 0x12345) {
- g_assert (ins21 == IA64_NOP_M);
- g_assert (ins23 == IA64_NOP_I);
- g_assert (ia64_ins_opcode (ins22) == 0);
- g_assert (ia64_ins_x3 (ins22) == 7);
- g_assert (ia64_ins_x (ins22) == 0);
- g_assert (ia64_ins_b1 (ins22) == IA64_B6);
-
- *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
-
- return regs [IA64_R11];
- }
-
- return NULL;
-}
-
gpointer*
-mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
+mono_arch_get_delegate_method_ptr_addr (guint8* code, mgreg_t *regs)
{
NOT_IMPLEMENTED;
}
void
-mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
+mono_arch_finish_init (void)
{
}
guint8 *start, *buf;
Ia64CodegenState code;
- g_assert (!fail_tramp);
-
size = count * 256;
buf = g_malloc0 (size);
ia64_codegen_init (code, buf);
ia64_begin_bundle (code);
item->code_target = (guint8*)code.buf + code.nins;
if (item->is_equals) {
- if (item->check_target_idx) {
- if (!item->compare_done) {
+ gboolean fail_case = !item->check_target_idx && fail_tramp;
+
+ if (item->check_target_idx || fail_case) {
+ if (!item->compare_done || fail_case) {
ia64_movl (code, GP_SCRATCH_REG, item->key);
ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
}
item->jmp_code = (guint8*)code.buf + code.nins;
ia64_br_cond_pred (code, 7, 0);
- ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
- ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
+ if (item->has_target_code) {
+ ia64_movl (code, GP_SCRATCH_REG, item->value.target_code);
+ } else {
+ ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
+ ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
+ }
ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
ia64_br_cond_reg (code, IA64_B6);
+
+ if (fail_case) {
+ ia64_begin_bundle (code);
+ ia64_patch (item->jmp_code, (guint8*)code.buf + code.nins);
+ ia64_movl (code, GP_SCRATCH_REG, fail_tramp);
+ ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
+ ia64_br_cond_reg (code, IA64_B6);
+ item->jmp_code = NULL;
+ }
} else {
/* enable the commented code to assert on wrong method */
#if ENABLE_WRONG_METHOD_CHECK
g_assert (code.buf - buf <= size);
size = code.buf - buf;
- start = mono_domain_code_reserve (domain, size);
+ if (fail_tramp) {
+ start = mono_method_alloc_generic_virtual_thunk (domain, size + 16);
+ start = (gpointer)ALIGN_TO (start, 16);
+ } else {
+ start = mono_domain_code_reserve (domain, size);
+ }
memcpy (start, buf, size);
mono_arch_flush_icache (start, size);
}
MonoMethod*
-mono_arch_find_imt_method (gpointer *regs, guint8 *code)
+mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
{
- return regs [IA64_R9];
+ return (MonoMethod*)regs [IA64_R9];
}
void
#endif
gpointer
-mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
{
return (gpointer)regs [IA64_R10];
}
-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);
-}
-
gpointer
mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
{
return mono_get_domain_intrinsic (cfg);
}
-MonoInst*
-mono_arch_get_thread_intrinsic (MonoCompile* cfg)
-{
- return mono_get_thread_intrinsic (cfg);
-}
-
-gpointer
+mgreg_t
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
/* FIXME: implement */