X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-amd64.c;h=b1cdaaf8dfe52c3628d5cf17cbd099beac77bf86;hb=ff49850dfc18f5991246a203184fa1e0b8a7c7ab;hp=11eb6cecf251e28b5bb87f74e498ad62bedf9088;hpb=2dc628d36f9ebd44d25126bfba00cffc6c2df8e4;p=mono.git diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 11eb6cecf25..b1cdaaf8dfe 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -495,14 +495,17 @@ typedef enum { typedef struct { gint16 offset; gint8 reg; - ArgStorage storage; + ArgStorage storage : 8; + gboolean is_gsharedvt_return_value : 1; /* Only if storage == ArgValuetypeInReg */ ArgStorage pair_storage [2]; gint8 pair_regs [2]; - /* The size of each pair */ + /* The size of each pair (bytes) */ int pair_size [2]; int nregs; + /* Only if storage == ArgOnStack */ + int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary } ArgInfo; typedef struct { @@ -520,16 +523,6 @@ typedef struct { #define DEBUG(a) if (cfg->verbose_level > 1) a -#ifdef TARGET_WIN32 -static AMD64_Reg_No param_regs [] = { AMD64_RCX, AMD64_RDX, AMD64_R8, AMD64_R9 }; - -static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX }; -#else -static AMD64_Reg_No param_regs [] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 }; - - static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX }; -#endif - static void inline add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo) { @@ -537,6 +530,7 @@ add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo) if (*gr >= PARAM_REGS) { ainfo->storage = ArgOnStack; + ainfo->arg_size = sizeof (mgreg_t); /* Since the same stack slot size is used for all arg */ /* types, it needs to be big enough to hold them all */ (*stack_size) += sizeof(mgreg_t); @@ -548,12 +542,6 @@ add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo) } } -#ifdef TARGET_WIN32 -#define FLOAT_PARAM_REGS 4 -#else -#define FLOAT_PARAM_REGS 8 -#endif - static void inline add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double) { @@ -561,6 +549,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double) if (*gr >= FLOAT_PARAM_REGS) { ainfo->storage = ArgOnStack; + ainfo->arg_size = sizeof (mgreg_t); /* Since the same stack slot size is used for both float */ /* types, it needs to be big enough to hold them both */ (*stack_size) += sizeof(mgreg_t); @@ -771,6 +760,8 @@ add_valuetype_win64 (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, ainfo->offset = *stack_size; *stack_size += ALIGN_TO (size, 8); ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack; + if (!is_return) + ainfo->arg_size = ALIGN_TO (size, 8); g_free (fields); return; @@ -815,6 +806,7 @@ add_valuetype_win64 (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, else { ainfo->pair_storage [0] = ArgOnStack; ainfo->offset = *stack_size; + ainfo->arg_size = sizeof (mgreg_t); *stack_size += 8; } } @@ -899,6 +891,8 @@ add_valuetype_win64 (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, ainfo->offset = *stack_size; *stack_size += sizeof (mgreg_t); ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack; + if (!is_return) + ainfo->arg_size = sizeof (mgreg_t); } } } @@ -969,6 +963,8 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, ainfo->offset = *stack_size; *stack_size += ALIGN_TO (size, 8); ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack; + if (!is_return) + ainfo->arg_size = ALIGN_TO (size, 8); g_free (fields); return; @@ -1011,6 +1007,8 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, ainfo->offset = *stack_size; *stack_size += ALIGN_TO (info->native_size, 8); ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack; + if (!is_return) + ainfo->arg_size = ALIGN_TO (info->native_size, 8); g_free (fields); return; @@ -1066,7 +1064,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, while (quadsize [0] != 1 && quadsize [0] != 2 && quadsize [0] != 4 && quadsize [0] != 8) quadsize [0] ++; - while (quadsize [1] != 1 && quadsize [1] != 2 && quadsize [1] != 4 && quadsize [1] != 8) + while (quadsize [1] != 0 && quadsize [1] != 1 && quadsize [1] != 2 && quadsize [1] != 4 && quadsize [1] != 8) quadsize [1] ++; ainfo->storage = ArgValuetypeInReg; @@ -1109,16 +1107,20 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, } if ((args [0] == ARG_CLASS_MEMORY) || (args [1] == ARG_CLASS_MEMORY)) { + int arg_size; /* Revert possible register assignments */ *gr = orig_gr; *fr = orig_fr; ainfo->offset = *stack_size; if (sig->pinvoke) - *stack_size += ALIGN_TO (info->native_size, 8); + arg_size = ALIGN_TO (info->native_size, 8); else - *stack_size += nquads * sizeof(mgreg_t); + arg_size = nquads * sizeof(mgreg_t); + *stack_size += arg_size; ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack; + if (!is_return) + ainfo->arg_size = arg_size; } } #endif /* !TARGET_WIN32 */ @@ -1198,6 +1200,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } if (mini_is_gsharedvt_type (ret_type)) { cinfo->ret.storage = ArgValuetypeAddrInIReg; + cinfo->ret.is_gsharedvt_return_value = 1; break; } /* fall through */ @@ -1213,6 +1216,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case MONO_TYPE_MVAR: g_assert (mini_is_gsharedvt_type (ret_type)); cinfo->ret.storage = ArgValuetypeAddrInIReg; + cinfo->ret.is_gsharedvt_return_value = 1; break; case MONO_TYPE_VOID: break; @@ -1312,7 +1316,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) add_general (&gr, &stack_size, ainfo); break; } - if (mini_is_gsharedvt_type (ptype)) { + if (mini_is_gsharedvt_variable_type (ptype)) { /* gsharedvt arguments are passed by ref */ add_general (&gr, &stack_size, ainfo); if (ainfo->storage == ArgInIReg) @@ -1461,6 +1465,9 @@ mono_arch_init (void) mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception); mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind); mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip); +#if defined(ENABLE_GSHAREDVT) + mono_aot_register_jit_icall ("mono_amd64_start_gsharedvt_call", mono_amd64_start_gsharedvt_call); +#endif if (!mono_aot_only) bp_trampoline = mini_get_breakpoint_trampoline (); @@ -1896,6 +1903,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) case ArgInDoubleSSEReg: cfg->ret->opcode = OP_REGVAR; cfg->ret->inst_c0 = cinfo->ret.reg; + cfg->ret->dreg = cinfo->ret.reg; break; case ArgValuetypeAddrInIReg: /* The register is volatile */ @@ -1928,15 +1936,13 @@ mono_arch_allocate_vars (MonoCompile *cfg) default: g_assert_not_reached (); } - cfg->ret->dreg = cfg->ret->inst_c0; } /* Allocate locals */ offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align); if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) { char *mname = mono_method_full_name (cfg->method, TRUE); - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; - cfg->exception_message = g_strdup_printf ("Method %s stack is too big.", mname); + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s stack is too big.", mname)); g_free (mname); return; } @@ -2038,7 +2044,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) NOT_IMPLEMENTED; } - if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg)) { + if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg) && (ainfo->storage != ArgGSharedVtOnStack)) { ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; /* These arguments are saved to the stack in the prolog */ @@ -2365,6 +2371,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) t = sig->params [i - sig->hasthis]; t = mini_get_underlying_type (t); + //XXX what about ArgGSharedVtOnStack here? if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) { if (!t->byref) { if (t->type == MONO_TYPE_R4) @@ -2426,6 +2433,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) /* Already emitted above */ break; + //FIXME what about ArgGSharedVtOnStack ? if (ainfo->storage == ArgOnStack && call->tail_call) { MonoInst *call_inst = (MonoInst*)call; cfg->args [i]->flags |= MONO_INST_VOLATILE; @@ -2450,8 +2458,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (size >= 10000) { /* Avoid asserts in emit_memcpy () */ - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; - cfg->exception_message = g_strdup_printf ("Passing an argument of size '%d'.", size); + mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Passing an argument of size '%d'.", size)); /* Continue normally */ } @@ -2604,7 +2611,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) mono_call_inst_add_outarg_reg (cfg, call, src->dreg, ainfo->reg, FALSE); break; case ArgGSharedVtOnStack: - g_assert_not_reached (); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, src->dreg); break; default: if (size == 8) { @@ -2676,6 +2683,8 @@ dyn_call_supported (MonoMethodSignature *sig, CallInfo *cinfo) switch (cinfo->ret.storage) { case ArgNone: case ArgInIReg: + case ArgInFloatSSEReg: + case ArgInDoubleSSEReg: break; case ArgValuetypeInReg: { ArgInfo *ainfo = &cinfo->ret; @@ -2694,6 +2703,8 @@ dyn_call_supported (MonoMethodSignature *sig, CallInfo *cinfo) ArgInfo *ainfo = &cinfo->args [i]; switch (ainfo->storage) { case ArgInIReg: + case ArgInFloatSSEReg: + case ArgInDoubleSSEReg: break; case ArgValuetypeInReg: if (ainfo->pair_storage [0] != ArgNone && ainfo->pair_storage [0] != ArgInIReg) @@ -2780,7 +2791,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g { ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info; DynCallArgs *p = (DynCallArgs*)buf; - int arg_index, greg, i, pindex; + int arg_index, greg, freg, i, pindex; MonoMethodSignature *sig = dinfo->sig; int buffer_offset = 0; @@ -2791,6 +2802,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g arg_index = 0; greg = 0; + freg = 0; pindex = 0; if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) { @@ -2852,6 +2864,18 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g case MONO_TYPE_U4: p->regs [greg ++] = *(guint32*)(arg); break; + case MONO_TYPE_R4: { + double d; + + *(float*)&d = *(float*)(arg); + p->has_fp = 1; + p->fregs [freg ++] = d; + break; + } + case MONO_TYPE_R8: + p->has_fp = 1; + p->fregs [freg ++] = *(double*)(arg); + break; case MONO_TYPE_GENERICINST: if (MONO_TYPE_IS_REFERENCE (t)) { p->regs [greg ++] = PTR_TO_GREG(*(arg)); @@ -2911,8 +2935,9 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf) { ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info; MonoMethodSignature *sig = dinfo->sig; - guint8 *ret = ((DynCallArgs*)buf)->ret; - mgreg_t res = ((DynCallArgs*)buf)->res; + DynCallArgs *dargs = (DynCallArgs*)buf; + guint8 *ret = dargs->ret; + mgreg_t res = dargs->res; MonoType *sig_ret = mini_get_underlying_type (sig->ret); switch (sig_ret->type) { @@ -2953,6 +2978,12 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf) case MONO_TYPE_U8: *(guint64*)ret = res; break; + case MONO_TYPE_R4: + *(float*)ret = *(float*)&(dargs->fregs [0]); + break; + case MONO_TYPE_R8: + *(double*)ret = dargs->fregs [0]; + break; case MONO_TYPE_GENERICINST: if (MONO_TYPE_IS_REFERENCE (sig_ret)) { *(gpointer*)ret = GREG_TO_PTR(res); @@ -3895,21 +3926,6 @@ emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offse return code; } -#define REAL_PRINT_REG(text,reg) \ -mono_assert (reg >= 0); \ -amd64_push_reg (code, AMD64_RAX); \ -amd64_push_reg (code, AMD64_RDX); \ -amd64_push_reg (code, AMD64_RCX); \ -amd64_push_reg (code, reg); \ -amd64_push_imm (code, reg); \ -amd64_push_imm (code, text " %d %p\n"); \ -amd64_mov_reg_imm (code, AMD64_RAX, printf); \ -amd64_call_reg (code, AMD64_RAX); \ -amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 3*4); \ -amd64_pop_reg (code, AMD64_RCX); \ -amd64_pop_reg (code, AMD64_RDX); \ -amd64_pop_reg (code, AMD64_RAX); - /* benchmark and set based on cpu */ #define LOOP_ALIGNMENT 8 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting) @@ -4991,6 +5007,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_DYN_CALL: { int i; MonoInst *var = cfg->dyn_call_var; + guint8 *label; g_assert (var->opcode == OP_REGOFFSET); @@ -5002,6 +5019,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Save args buffer */ amd64_mov_membase_reg (code, var->inst_basereg, var->inst_offset, AMD64_R11, 8); + /* Set fp arg regs */ + amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, has_fp), sizeof (mgreg_t)); + amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX); + label = code; + amd64_branch8 (code, X86_CC_Z, -1, 1); + for (i = 0; i < FLOAT_PARAM_REGS; ++i) + amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, fregs) + (i * sizeof (double))); + amd64_patch (label, code); + /* Set argument registers */ for (i = 0; i < PARAM_REGS; ++i) amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof(mgreg_t), sizeof(mgreg_t)); @@ -5015,6 +5041,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Save result */ amd64_mov_reg_membase (code, AMD64_R11, var->inst_basereg, var->inst_offset, 8); amd64_mov_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, res), AMD64_RAX, 8); + amd64_sse_movsd_membase_reg (code, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, fregs), AMD64_XMM0); break; } case OP_AMD64_SAVE_SP_TO_LMF: { @@ -5870,7 +5897,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_alu_reg_imm (code, X86_CMP, AMD64_RAX, X86_FP_C0); amd64_pop_reg (code, AMD64_RAX); amd64_fstp (code, 0); - EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException"); + EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException"); amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 16); break; case OP_TLS_GET: { @@ -7037,11 +7064,15 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* Stack alignment check */ #if 0 { + guint8 *buf; + amd64_mov_reg_reg (code, AMD64_RAX, AMD64_RSP, 8); amd64_alu_reg_imm (code, X86_AND, AMD64_RAX, 0xf); amd64_alu_reg_imm (code, X86_CMP, AMD64_RAX, 0); - x86_branch8 (code, X86_CC_EQ, 2, FALSE); + buf = code; + x86_branch8 (code, X86_CC_EQ, 1, FALSE); amd64_breakpoint (code); + amd64_patch (buf, code); } #endif @@ -7239,6 +7270,9 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (ainfo->pair_storage [0] == ArgInIReg) amd64_mov_membase_reg (code, ins->inst_left->inst_basereg, ins->inst_left->inst_offset, ainfo->pair_regs [0], sizeof (gpointer)); break; + case ArgGSharedVtInReg: + amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg, 8); + break; default: break; } @@ -7548,8 +7582,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) amd64_patch (patch_info->ip.i + cfg->native_code, code); - exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name); - g_assert (exc_class); + exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name); throw_ip = patch_info->ip.i; //x86_breakpoint (code); @@ -8816,4 +8849,4 @@ mono_arch_opcode_supported (int opcode) #include "../../../mono-extensions/mono/mini/mini-amd64-gsharedvt.c" -#endif /* !MONOTOUCH */ +#endif /* !ENABLE_GSHAREDVT */