#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-tls.h>
+#include <mono/utils/mono-hwcap-x86.h>
#include "trace.h"
#include "ir-emit.h"
#include "debugger-agent.h"
#include "mini-gc.h"
-static gint lmf_tls_offset = -1;
-static gint lmf_addr_tls_offset = -1;
-static gint appdomain_tls_offset = -1;
+#ifdef HOST_WIN32
+static gint jit_tls_offset = -1;
+#endif
#ifdef MONO_XEN_OPT
static gboolean optimize_for_xen = TRUE;
} ArgumentClass;
static ArgumentClass
-merge_argument_class_from_type (MonoType *type, ArgumentClass class1)
+merge_argument_class_from_type (MonoGenericSharingContext *gsctx, MonoType *type, ArgumentClass class1)
{
ArgumentClass class2 = ARG_CLASS_NO_CLASS;
MonoType *ptype;
- ptype = mini_type_get_underlying_type (NULL, type);
+ ptype = mini_type_get_underlying_type (gsctx, type);
switch (ptype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_CHAR:
for (i = 0; i < info->num_fields; ++i) {
class2 = class1;
- class2 = merge_argument_class_from_type (info->fields [i].field->type, class2);
+ class2 = merge_argument_class_from_type (gsctx, info->fields [i].field->type, class2);
}
break;
}
/* (8 is size of quad) */
quadsize [quad] = info->fields [i].offset + size - (quad * 8);
- class1 = merge_argument_class_from_type (info->fields [i].field->type, class1);
+ class1 = merge_argument_class_from_type (gsctx, info->fields [i].field->type, class1);
}
g_assert (class1 != ARG_CLASS_NO_CLASS);
args [quad] = class1;
case MONO_TYPE_VALUETYPE: {
guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
- add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
+ add_valuetype (gsctx, sig, &cinfo->ret, ret_type, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
if (cinfo->ret.storage == ArgOnStack) {
cinfo->vtype_retaddr = TRUE;
/* The caller passes the address where the value is stored */
case MONO_TYPE_VOID:
break;
default:
- g_error ("Can't handle as return value 0x%x", sig->ret->type);
+ g_error ("Can't handle as return value 0x%x", ret_type->type);
}
}
}
gboolean
-mono_amd64_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
+mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
{
CallInfo *c1, *c2;
gboolean res;
+ MonoType *callee_ret;
c1 = get_call_info (NULL, NULL, caller_sig);
c2 = get_call_info (NULL, NULL, callee_sig);
res = c1->stack_usage >= c2->stack_usage;
- if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret) && c2->ret.storage != ArgValuetypeInReg)
+ callee_ret = mini_replace_type (callee_sig->ret);
+ if (callee_ret && MONO_TYPE_ISSTRUCT (callee_ret) && c2->ret.storage != ArgValuetypeInReg)
/* An address on the callee's stack is passed as the first argument */
res = FALSE;
return res;
}
-static int
-cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
-{
-#if defined(MONO_CROSS_COMPILE)
- return 0;
-#else
-#ifndef _MSC_VER
- __asm__ __volatile__ ("cpuid"
- : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
- : "a" (id));
-#else
- int info[4];
- __cpuid(info, id);
- *p_eax = info[0];
- *p_ebx = info[1];
- *p_ecx = info[2];
- *p_edx = info[3];
-#endif
- return 1;
-#endif
-}
-
/*
* Initialize the cpu to execute managed code.
*/
guint32
mono_arch_cpu_optimizations (guint32 *exclude_mask)
{
- int eax, ebx, ecx, edx;
guint32 opts = 0;
*exclude_mask = 0;
- /* Feature Flags function, flags returned in EDX. */
- if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
- if (edx & (1 << 15)) {
- opts |= MONO_OPT_CMOV;
- if (edx & 1)
- opts |= MONO_OPT_FCMOV;
- else
- *exclude_mask |= MONO_OPT_FCMOV;
- } else
- *exclude_mask |= MONO_OPT_CMOV;
+
+ if (mono_hwcap_x86_has_cmov) {
+ opts |= MONO_OPT_CMOV;
+
+ if (mono_hwcap_x86_has_fcmov)
+ opts |= MONO_OPT_FCMOV;
+ else
+ *exclude_mask |= MONO_OPT_FCMOV;
+ } else {
+ *exclude_mask |= MONO_OPT_CMOV;
}
return opts;
guint32
mono_arch_cpu_enumerate_simd_versions (void)
{
- int eax, ebx, ecx, edx;
guint32 sse_opts = 0;
- if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
- if (edx & (1 << 25))
- sse_opts |= SIMD_VERSION_SSE1;
- if (edx & (1 << 26))
- sse_opts |= SIMD_VERSION_SSE2;
- if (ecx & (1 << 0))
- sse_opts |= SIMD_VERSION_SSE3;
- if (ecx & (1 << 9))
- sse_opts |= SIMD_VERSION_SSSE3;
- if (ecx & (1 << 19))
- sse_opts |= SIMD_VERSION_SSE41;
- if (ecx & (1 << 20))
- sse_opts |= SIMD_VERSION_SSE42;
- }
-
- /* Yes, all this needs to be done to check for sse4a.
- See: "Amd: CPUID Specification"
- */
- if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
- /* eax greater or equal than 0x80000001, ebx = 'htuA', ecx = DMAc', edx = 'itne'*/
- if ((((unsigned int) eax) >= 0x80000001) && (ebx == 0x68747541) && (ecx == 0x444D4163) && (edx == 0x69746E65)) {
- cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
- if (ecx & (1 << 6))
- sse_opts |= SIMD_VERSION_SSE4a;
- }
- }
+ if (mono_hwcap_x86_has_sse1)
+ sse_opts |= SIMD_VERSION_SSE1;
+
+ if (mono_hwcap_x86_has_sse2)
+ sse_opts |= SIMD_VERSION_SSE2;
+
+ if (mono_hwcap_x86_has_sse3)
+ sse_opts |= SIMD_VERSION_SSE3;
- return sse_opts;
+ if (mono_hwcap_x86_has_ssse3)
+ sse_opts |= SIMD_VERSION_SSSE3;
+
+ if (mono_hwcap_x86_has_sse41)
+ sse_opts |= SIMD_VERSION_SSE41;
+
+ if (mono_hwcap_x86_has_sse42)
+ sse_opts |= SIMD_VERSION_SSE42;
+
+ if (mono_hwcap_x86_has_sse4a)
+ sse_opts |= SIMD_VERSION_SSE4a;
+
+ return sse_opts;
}
#ifndef DISABLE_JIT
void
mono_arch_fill_argument_info (MonoCompile *cfg)
{
+ MonoType *sig_ret;
MonoMethodSignature *sig;
MonoMethodHeader *header;
MonoInst *ins;
sig = mono_method_signature (cfg->method);
cinfo = cfg->arch.cinfo;
+ sig_ret = mini_replace_type (sig->ret);
/*
* Contrary to mono_arch_allocate_vars (), the information should describe
* accessed during the execution of the method. The later makes no sense for the
* global register allocator, since a variable can be in more than one location.
*/
- if (sig->ret->type != MONO_TYPE_VOID) {
+ if (sig_ret->type != MONO_TYPE_VOID) {
switch (cinfo->ret.storage) {
case ArgInIReg:
case ArgInFloatSSEReg:
case ArgInDoubleSSEReg:
- if ((MONO_TYPE_ISSTRUCT (sig->ret) && !mono_class_from_mono_type (sig->ret)->enumtype) || ((sig->ret->type == MONO_TYPE_TYPEDBYREF) && cinfo->vtype_retaddr)) {
+ if ((MONO_TYPE_ISSTRUCT (sig_ret) && !mono_class_from_mono_type (sig_ret)->enumtype) || ((sig_ret->type == MONO_TYPE_TYPEDBYREF) && cinfo->vtype_retaddr)) {
cfg->vret_addr->opcode = OP_REGVAR;
cfg->vret_addr->inst_c0 = cinfo->ret.reg;
}
void
mono_arch_allocate_vars (MonoCompile *cfg)
{
+ MonoType *sig_ret;
MonoMethodSignature *sig;
MonoMethodHeader *header;
MonoInst *ins;
sig = mono_method_signature (cfg->method);
cinfo = cfg->arch.cinfo;
+ sig_ret = mini_replace_type (sig->ret);
mono_arch_compute_omit_fp (cfg);
if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
offset += sizeof(mgreg_t);
}
+ if (!cfg->arch.omit_fp)
+ cfg->arch.reg_save_area_offset = -offset;
}
- if (sig->ret->type != MONO_TYPE_VOID) {
+ if (sig_ret->type != MONO_TYPE_VOID) {
switch (cinfo->ret.storage) {
case ArgInIReg:
case ArgInFloatSSEReg:
case ArgInDoubleSSEReg:
- if ((MONO_TYPE_ISSTRUCT (sig->ret) && !mono_class_from_mono_type (sig->ret)->enumtype) || ((sig->ret->type == MONO_TYPE_TYPEDBYREF) && cinfo->vtype_retaddr)) {
+ if ((MONO_TYPE_ISSTRUCT (sig_ret) && !mono_class_from_mono_type (sig_ret)->enumtype) || ((sig_ret->type == MONO_TYPE_TYPEDBYREF) && cinfo->vtype_retaddr)) {
if (cfg->globalra) {
cfg->vret_addr->opcode = OP_REGVAR;
cfg->vret_addr->inst_c0 = cinfo->ret.reg;
{
MonoMethodSignature *sig;
CallInfo *cinfo;
+ MonoType *sig_ret;
sig = mono_method_signature (cfg->method);
if (cinfo->ret.storage == ArgValuetypeInReg)
cfg->ret_var_is_local = TRUE;
- if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig->ret)) {
+ sig_ret = mini_replace_type (sig->ret);
+ if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig_ret)) {
cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
if (G_UNLIKELY (cfg->verbose_level > 1)) {
printf ("vret_addr = ");
cfg->arch.no_pushes = TRUE;
#endif
+ if (cfg->method->save_lmf)
+ cfg->create_lmf_var = TRUE;
+
+#if !defined(HOST_WIN32)
if (cfg->method->save_lmf) {
- MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- lmf_var->flags |= MONO_INST_VOLATILE;
- lmf_var->flags |= MONO_INST_LMF;
- cfg->arch.lmf_var = lmf_var;
+ cfg->lmf_ir = TRUE;
+ if (mono_get_lmf_tls_offset () != -1 && !optimize_for_xen)
+ cfg->lmf_ir_mono_lmf = TRUE;
}
+#endif
#ifndef MONO_AMD64_NO_PUSHES
cfg->arch_eh_jit_info = 1;
ArgInfo *ainfo;
int j;
LLVMCallInfo *linfo;
- MonoType *t;
+ MonoType *t, *sig_ret;
n = sig->param_count + sig->hasthis;
+ sig_ret = mini_replace_type (sig->ret);
cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
linfo->ret.pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, cinfo->ret.pair_storage [j]);
}
- if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage == ArgInIReg) {
+ if (MONO_TYPE_ISSTRUCT (sig_ret) && cinfo->ret.storage == ArgInIReg) {
/* Vtype returned using a hidden argument */
linfo->ret.storage = LLVMArgVtypeRetAddr;
linfo->vret_arg_index = cinfo->vret_arg_index;
{
MonoInst *arg, *in;
MonoMethodSignature *sig;
+ MonoType *sig_ret;
int i, n, stack_size;
CallInfo *cinfo;
ArgInfo *ainfo;
cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
+ sig_ret = sig->ret;
+
if (COMPILE_LLVM (cfg)) {
/* We shouldn't be called in the llvm case */
cfg->disable_llvm = TRUE;
if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
emit_sig_cookie (cfg, call, cinfo);
- if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
+ sig_ret = mini_replace_type (sig->ret);
+ if (sig_ret && MONO_TYPE_ISSTRUCT (sig_ret)) {
MonoInst *vtarg;
if (cinfo->ret.storage == ArgValuetypeInReg) {
}
#ifdef HOST_WIN32
- if (call->inst.opcode != OP_JMP && OP_TAILCALL != call->inst.opcode) {
+ if (call->inst.opcode != OP_TAILCALL) {
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 0x20);
}
#endif
g_assert (!cfg->arch.no_pushes);
MONO_INST_NEW (cfg, load, OP_LDADDR);
+ cfg->has_indirection = TRUE;
load->inst_p0 = vtaddr;
vtaddr->flags |= MONO_INST_INDIRECT;
load->type = STACK_MP;
void
mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
{
- MonoType *ret = mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret);
+ MonoType *ret = mini_replace_type (mono_method_signature (method)->ret);
if (ret->type == MONO_TYPE_R4) {
if (COMPILE_LLVM (cfg))
MonoMethodSignature *sig = dinfo->sig;
guint8 *ret = ((DynCallArgs*)buf)->ret;
mgreg_t res = ((DynCallArgs*)buf)->res;
+ MonoType *sig_ret = mono_type_get_underlying_type (sig->ret);
- switch (mono_type_get_underlying_type (sig->ret)->type) {
+ switch (sig_ret->type) {
case MONO_TYPE_VOID:
*(gpointer*)ret = NULL;
break;
*(guint64*)ret = res;
break;
case MONO_TYPE_GENERICINST:
- if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
+ if (MONO_TYPE_IS_REFERENCE (sig_ret)) {
*(gpointer*)ret = GREG_TO_PTR(res);
break;
} else {
#endif
}
+int
+mono_amd64_get_tls_gs_offset (void)
+{
+#ifdef TARGET_OSX
+ return tls_gs_offset;
+#else
+ g_assert_not_reached ();
+ return -1;
+#endif
+}
+
/*
* mono_amd64_emit_tls_get:
* @code: buffer to store code to
return code;
}
+static guint8*
+emit_tls_get_reg (guint8* code, int dreg, int offset_reg)
+{
+ /* offset_reg contains a value translated by mono_arch_translate_tls_offset () */
+#ifdef TARGET_OSX
+ if (dreg != offset_reg)
+ amd64_mov_reg_reg (code, dreg, offset_reg, sizeof (mgreg_t));
+ amd64_prefix (code, X86_GS_PREFIX);
+ amd64_mov_reg_membase (code, dreg, dreg, 0, sizeof (mgreg_t));
+#elif defined(__linux__)
+ int tmpreg = -1;
+
+ if (dreg == offset_reg) {
+ /* Use a temporary reg by saving it to the redzone */
+ tmpreg = dreg == AMD64_RAX ? AMD64_RCX : AMD64_RAX;
+ amd64_mov_membase_reg (code, AMD64_RSP, -8, tmpreg, 8);
+ amd64_mov_reg_reg (code, tmpreg, offset_reg, sizeof (gpointer));
+ offset_reg = tmpreg;
+ }
+ x86_prefix (code, X86_FS_PREFIX);
+ amd64_mov_reg_mem (code, dreg, 0, 8);
+ amd64_mov_reg_memindex (code, dreg, dreg, 0, offset_reg, 0, 8);
+ if (tmpreg != -1)
+ amd64_mov_reg_membase (code, tmpreg, AMD64_RSP, -8, 8);
+#else
+ g_assert_not_reached ();
+#endif
+ return code;
+}
+
+static guint8*
+amd64_emit_tls_set (guint8 *code, int sreg, int tls_offset)
+{
+#ifdef HOST_WIN32
+ g_assert_not_reached ();
+#elif defined(__APPLE__)
+ x86_prefix (code, X86_GS_PREFIX);
+ amd64_mov_mem_reg (code, tls_gs_offset + (tls_offset * 8), sreg, 8);
+#else
+ g_assert (!optimize_for_xen);
+ x86_prefix (code, X86_FS_PREFIX);
+ amd64_mov_mem_reg (code, tls_offset, sreg, 8);
+#endif
+ return code;
+}
+
+static guint8*
+amd64_emit_tls_set_reg (guint8 *code, int sreg, int offset_reg)
+{
+ /* offset_reg contains a value translated by mono_arch_translate_tls_offset () */
+#ifdef HOST_WIN32
+ g_assert_not_reached ();
+#elif defined(__APPLE__)
+ x86_prefix (code, X86_GS_PREFIX);
+ amd64_mov_membase_reg (code, offset_reg, 0, sreg, 8);
+#else
+ x86_prefix (code, X86_FS_PREFIX);
+ amd64_mov_membase_reg (code, offset_reg, 0, sreg, 8);
+#endif
+ return code;
+}
+
+ /*
+ * mono_arch_translate_tls_offset:
+ *
+ * Translate the TLS offset OFFSET computed by MONO_THREAD_VAR_OFFSET () into a format usable by OP_TLS_GET_REG/OP_TLS_SET_REG.
+ */
+int
+mono_arch_translate_tls_offset (int offset)
+{
+#ifdef __APPLE__
+ return tls_gs_offset + (offset * 8);
+#else
+ return offset;
+#endif
+}
+
/*
* emit_setup_lmf:
*
/* These can't contain refs */
mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF);
+#ifdef HOST_WIN32
mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF);
- mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF);
+#endif
mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rip), SLOT_NOREF);
mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), SLOT_NOREF);
return code;
}
+#ifdef HOST_WIN32
/*
- * emit_save_lmf:
+ * emit_push_lmf:
*
* Emit code to push an LMF structure on the LMF stack.
*/
static guint8*
-emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args_clobbered)
+emit_push_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args_clobbered)
{
- if ((lmf_tls_offset != -1) && !optimize_for_xen) {
- /*
- * Optimized version which uses the mono_lmf TLS variable instead of
- * indirection through the mono_lmf_addr TLS variable.
- */
- /* %rax = previous_lmf */
- x86_prefix (code, X86_FS_PREFIX);
- amd64_mov_reg_mem (code, AMD64_RAX, lmf_tls_offset, 8);
-
- /* Save previous_lmf */
- amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_RAX, 8);
- /* Set new lmf */
- if (lmf_offset == 0) {
- x86_prefix (code, X86_FS_PREFIX);
- amd64_mov_mem_reg (code, lmf_tls_offset, cfg->frame_reg, 8);
- } else {
- amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
- x86_prefix (code, X86_FS_PREFIX);
- amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
- }
+ if (jit_tls_offset != -1) {
+ code = mono_amd64_emit_tls_get (code, AMD64_RAX, jit_tls_offset);
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
} else {
- if (lmf_addr_tls_offset != -1) {
- /* Load lmf quicky using the FS register */
- code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
-#ifdef HOST_WIN32
- /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
- /* FIXME: Add a separate key for LMF to avoid this */
- amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
-#endif
- }
- else {
- /*
- * The call might clobber argument registers, but they are already
- * saved to the stack/global regs.
- */
- if (args_clobbered)
- *args_clobbered = TRUE;
- code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
- (gpointer)"mono_get_lmf_addr", TRUE);
- }
-
- /* Save lmf_addr */
- amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), AMD64_RAX, sizeof(gpointer));
- /* Save previous_lmf */
- amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, sizeof(gpointer));
- amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, sizeof(gpointer));
- /* Set new lmf */
- amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
- amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
+ /*
+ * The call might clobber argument registers, but they are already
+ * saved to the stack/global regs.
+ */
+ if (args_clobbered)
+ *args_clobbered = TRUE;
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_get_lmf_addr", TRUE);
}
+ /* Save lmf_addr */
+ amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), AMD64_RAX, sizeof(gpointer));
+ /* Save previous_lmf */
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, sizeof(gpointer));
+ amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, sizeof(gpointer));
+ /* Set new lmf */
+ amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
+ amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
+
return code;
}
+#endif
+#ifdef HOST_WIN32
/*
- * emit_save_lmf:
+ * emit_pop_lmf:
*
* Emit code to pop an LMF structure from the LMF stack.
*/
static guint8*
-emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
+emit_pop_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
{
- if ((lmf_tls_offset != -1) && !optimize_for_xen) {
- /*
- * Optimized version which uses the mono_lmf TLS variable instead of indirection
- * through the mono_lmf_addr TLS variable.
- */
- /* reg = previous_lmf */
- amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
- x86_prefix (code, X86_FS_PREFIX);
- amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
- } else {
- /* Restore previous lmf */
- amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
- amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof(gpointer));
- amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
- }
+ /* Restore previous lmf */
+ amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
+ amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof(gpointer));
+ amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
return code;
}
+#endif
#define REAL_PRINT_REG(text,reg) \
mono_assert (reg >= 0); \
}
case OP_TAILCALL: {
MonoCallInst *call = (MonoCallInst*)ins;
- int pos = 0, i;
+ int i, save_area_offset;
/* FIXME: no tracing support... */
if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
g_assert (!cfg->method->save_lmf);
- if (cfg->arch.omit_fp) {
- guint32 save_offset = 0;
- /* Pop callee-saved registers */
- for (i = 0; i < AMD64_NREG; ++i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_mov_reg_membase (code, i, AMD64_RSP, save_offset, 8);
- save_offset += 8;
- }
- amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, cfg->arch.stack_alloc_size);
+ /* Restore callee saved registers */
+ save_area_offset = cfg->arch.reg_save_area_offset;
+ for (i = 0; i < AMD64_NREG; ++i)
+ if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
+ amd64_mov_reg_membase (code, i, cfg->frame_reg, save_area_offset, 8);
+ save_area_offset += 8;
+ }
+ if (cfg->arch.omit_fp) {
+ if (cfg->arch.stack_alloc_size)
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, cfg->arch.stack_alloc_size);
// FIXME:
if (call->stack_usage)
NOT_IMPLEMENTED;
- }
- else {
- for (i = 0; i < AMD64_NREG; ++i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i)))
- pos -= sizeof(mgreg_t);
-
- /* Restore callee-saved registers */
- for (i = AMD64_NREG - 1; i > 0; --i) {
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_mov_reg_membase (code, i, AMD64_RBP, pos, sizeof(mgreg_t));
- pos += sizeof(mgreg_t);
- }
- }
-
+ } else {
/* Copy arguments on the stack to our argument area */
for (i = 0; i < call->stack_usage; i += sizeof(mgreg_t)) {
amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, i, sizeof(mgreg_t));
amd64_mov_membase_reg (code, AMD64_RBP, 16 + i, AMD64_RAX, sizeof(mgreg_t));
}
-
- if (pos)
- amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, pos);
amd64_leave (code);
}
break;
}
case OP_AMD64_SAVE_SP_TO_LMF: {
- MonoInst *lmf_var = cfg->arch.lmf_var;
- amd64_mov_membase_reg (code, cfg->frame_reg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
+ MonoInst *lmf_var = cfg->lmf_var;
+ amd64_mov_membase_reg (code, lmf_var->inst_basereg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
break;
}
case OP_X86_PUSH:
case OP_BR_REG:
amd64_jump_reg (code, ins->sreg1);
break;
+ case OP_ICNEQ:
+ case OP_ICGE:
+ case OP_ICLE:
+ case OP_ICGE_UN:
+ case OP_ICLE_UN:
+
case OP_CEQ:
case OP_LCEQ:
case OP_ICEQ:
amd64_sse_movss_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, ins->dreg);
break;
- case OP_ICONV_TO_R4: /* FIXME: change precision */
+ case OP_ICONV_TO_R4:
+ amd64_sse_cvtsi2ss_reg_reg_size (code, ins->dreg, ins->sreg1, 4);
+ amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, ins->dreg);
+ break;
case OP_ICONV_TO_R8:
amd64_sse_cvtsi2sd_reg_reg_size (code, ins->dreg, ins->sreg1, 4);
break;
- case OP_LCONV_TO_R4: /* FIXME: change precision */
+ case OP_LCONV_TO_R4:
+ amd64_sse_cvtsi2ss_reg_reg (code, ins->dreg, ins->sreg1);
+ amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, ins->dreg);
+ break;
case OP_LCONV_TO_R8:
amd64_sse_cvtsi2sd_reg_reg (code, ins->dreg, ins->sreg1);
break;
case OP_FCONV_TO_R4:
- /* FIXME: nothing to do ?? */
+ amd64_sse_cvtsd2ss_reg_reg (code, ins->dreg, ins->sreg1);
+ amd64_sse_cvtss2sd_reg_reg (code, ins->dreg, ins->dreg);
break;
case OP_FCONV_TO_I1:
code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
*/
amd64_sse_comisd_reg_reg (code, ins->sreg2, ins->sreg1);
break;
+ case OP_FCNEQ:
case OP_FCEQ: {
/* zeroing the register at the start results in
* shorter and faster code (we can also remove the widening op)
amd64_sse_comisd_reg_reg (code, ins->sreg1, ins->sreg2);
unordered_check = code;
x86_branch8 (code, X86_CC_P, 0, FALSE);
- amd64_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
- amd64_patch (unordered_check, code);
+
+ if (ins->opcode == OP_FCEQ) {
+ amd64_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
+ amd64_patch (unordered_check, code);
+ } else {
+ guchar *jump_to_end;
+ amd64_set_reg (code, X86_CC_NE, ins->dreg, FALSE);
+ jump_to_end = code;
+ x86_jump8 (code, 0);
+ amd64_patch (unordered_check, code);
+ amd64_inc_reg (code, ins->dreg);
+ amd64_patch (jump_to_end, code);
+ }
break;
}
case OP_FCLT:
amd64_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
}
break;
+ case OP_FCLE: {
+ guchar *unordered_check;
+ amd64_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
+ amd64_sse_comisd_reg_reg (code, ins->sreg2, ins->sreg1);
+ unordered_check = code;
+ x86_branch8 (code, X86_CC_P, 0, FALSE);
+ amd64_set_reg (code, X86_CC_NB, ins->dreg, FALSE);
+ amd64_patch (unordered_check, code);
+ break;
+ }
case OP_FCGT:
case OP_FCGT_UN: {
/* zeroing the register at the start results in
}
break;
}
+ case OP_FCGE: {
+ guchar *unordered_check;
+ amd64_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
+ amd64_sse_comisd_reg_reg (code, ins->sreg2, ins->sreg1);
+ unordered_check = code;
+ x86_branch8 (code, X86_CC_P, 0, FALSE);
+ amd64_set_reg (code, X86_CC_NA, ins->dreg, FALSE);
+ amd64_patch (unordered_check, code);
+ break;
+ }
+
case OP_FCLT_MEMBASE:
case OP_FCGT_MEMBASE:
case OP_FCLT_UN_MEMBASE:
code = mono_amd64_emit_tls_get (code, ins->dreg, ins->inst_offset);
break;
}
+ case OP_TLS_GET_REG:
+ code = emit_tls_get_reg (code, ins->dreg, ins->sreg1);
+ break;
+ case OP_TLS_SET: {
+ code = amd64_emit_tls_set (code, ins->sreg1, ins->inst_offset);
+ break;
+ }
+ case OP_TLS_SET_REG: {
+ code = amd64_emit_tls_set_reg (code, ins->sreg1, ins->sreg2);
+ break;
+ }
case OP_MEMORY_BARRIER: {
switch (ins->backend.memory_barrier_kind) {
case StoreLoadBarrier:
case OP_CARD_TABLE_WBARRIER: {
int ptr = ins->sreg1;
int value = ins->sreg2;
- guchar *br;
+ guchar *br = 0;
int nursery_shift, card_table_shift;
gpointer card_table_mask;
size_t nursery_size;
amd64_alu_reg_membase (code, X86_ADD, AMD64_RDX, AMD64_RIP, 0);
amd64_mov_membase_imm (code, AMD64_RDX, 0, 1, 1);
+
if (mono_gc_card_table_nursery_check ())
x86_patch (br, code);
break;
unsigned char *ip = patch_info->ip.i + code;
unsigned char *target;
- target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
-
if (compile_aot) {
switch (patch_info->type) {
case MONO_PATCH_INFO_BB:
}
}
+ target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+
switch (patch_info->type) {
case MONO_PATCH_INFO_NONE:
continue;
int alloc_size, pos, i, cfa_offset, quad, max_epilog_size;
guint8 *code;
CallInfo *cinfo;
- MonoInst *lmf_var = cfg->arch.lmf_var;
+ MonoInst *lmf_var = cfg->lmf_var;
gboolean args_clobbered = FALSE;
gboolean trace = FALSE;
#ifdef __native_client_codegen__
#endif
}
- /* Save callee saved registers */
- if (!cfg->arch.omit_fp && !method->save_lmf) {
- int offset = cfa_offset;
-
- for (i = 0; i < AMD64_NREG; ++i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_push_reg (code, i);
- pos += 8; /* AMD64 push inst is always 8 bytes, no way to change it */
- offset += 8;
- mono_emit_unwind_op_offset (cfg, code, i, - offset);
- async_exc_point (code);
-
- /* These are handled automatically by the stack marking code */
- mini_gc_set_slot_type_from_cfa (cfg, - offset, SLOT_NOREF);
- }
- }
-
/* The param area is always at offset 0 from sp */
/* This needs to be allocated here, since it has to come after the spill area */
if (cfg->arch.no_pushes && cfg->param_area) {
}
/* Save callee saved registers */
- if (cfg->arch.omit_fp && !method->save_lmf) {
- gint32 save_area_offset = cfg->arch.reg_save_area_offset;
+ if (!method->save_lmf) {
+ gint32 save_area_offset;
+
+ if (cfg->arch.omit_fp) {
+ save_area_offset = cfg->arch.reg_save_area_offset;
+ /* Save caller saved registers after sp is adjusted */
+ /* The registers are saved at the bottom of the frame */
+ /* FIXME: Optimize this so the regs are saved at the end of the frame in increasing order */
+ } else {
+ /* The registers are saved just below the saved rbp */
+ save_area_offset = cfg->arch.reg_save_area_offset;
+ }
- /* Save caller saved registers after sp is adjusted */
- /* The registers are saved at the bottom of the frame */
- /* FIXME: Optimize this so the regs are saved at the end of the frame in increasing order */
for (i = 0; i < AMD64_NREG; ++i)
if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_mov_membase_reg (code, AMD64_RSP, save_area_offset, i, 8);
- mono_emit_unwind_op_offset (cfg, code, i, - (cfa_offset - save_area_offset));
+ amd64_mov_membase_reg (code, cfg->frame_reg, save_area_offset, i, 8);
- /* These are handled automatically by the stack marking code */
- mini_gc_set_slot_type_from_cfa (cfg, - (cfa_offset - save_area_offset), SLOT_NOREF);
+ if (cfg->arch.omit_fp) {
+ mono_emit_unwind_op_offset (cfg, code, i, - (cfa_offset - save_area_offset));
+ /* These are handled automatically by the stack marking code */
+ mini_gc_set_slot_type_from_cfa (cfg, - (cfa_offset - save_area_offset), SLOT_NOREF);
+ } else {
+ mono_emit_unwind_op_offset (cfg, code, i, - (-save_area_offset + (2 * 8)));
+ // FIXME: GC
+ }
save_area_offset += 8;
async_exc_point (code);
}
}
+#ifdef HOST_WIN32
if (method->save_lmf) {
- code = emit_save_lmf (cfg, code, lmf_var->inst_offset, &args_clobbered);
+ code = emit_push_lmf (cfg, code, lmf_var->inst_offset, &args_clobbered);
}
+#else
+ args_clobbered = TRUE;
+#endif
if (trace) {
args_clobbered = TRUE;
guint8 *code;
int max_epilog_size;
CallInfo *cinfo;
- gint32 lmf_offset = cfg->arch.lmf_var ? ((MonoInst*)cfg->arch.lmf_var)->inst_offset : -1;
+ gint32 lmf_offset = cfg->lmf_var ? ((MonoInst*)cfg->lmf_var)->inst_offset : -1;
max_epilog_size = get_max_epilog_size (cfg);
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
- /* the code restoring the registers must be kept in sync with OP_JMP */
+ /* the code restoring the registers must be kept in sync with OP_TAILCALL */
pos = 0;
if (method->save_lmf) {
+#ifdef HOST_WIN32
+ code = emit_pop_lmf (cfg, code, lmf_offset);
+#endif
+
/* check if we need to restore protection of the stack after a stack overflow */
if (mono_get_jit_tls_offset () != -1) {
guint8 *patch;
/* FIXME: maybe save the jit tls in the prolog */
}
- code = emit_restore_lmf (cfg, code, lmf_offset);
-
/* Restore caller saved regs */
if (cfg->used_int_regs & (1 << AMD64_RBP)) {
amd64_mov_reg_membase (code, AMD64_RBP, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rbp), 8);
}
#endif
} else {
+ gint32 save_area_offset = cfg->arch.reg_save_area_offset;
- if (cfg->arch.omit_fp) {
- gint32 save_area_offset = cfg->arch.reg_save_area_offset;
-
- for (i = 0; i < AMD64_NREG; ++i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_mov_reg_membase (code, i, AMD64_RSP, save_area_offset, 8);
- save_area_offset += 8;
- }
- }
- else {
- for (i = 0; i < AMD64_NREG; ++i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i)))
- pos -= sizeof(mgreg_t);
-
- if (pos) {
- if (pos == - sizeof(mgreg_t)) {
- /* Only one register, so avoid lea */
- for (i = AMD64_NREG - 1; i > 0; --i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_mov_reg_membase (code, i, AMD64_RBP, pos, 8);
- }
- }
- else {
- amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, pos);
-
- /* Pop registers in reverse order */
- for (i = AMD64_NREG - 1; i > 0; --i)
- if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
- amd64_pop_reg (code, i);
- }
- }
+ for (i = 0; i < AMD64_NREG; ++i)
+ if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
+ amd64_mov_reg_membase (code, i, cfg->frame_reg, save_area_offset, 8);
+ save_area_offset += 8;
}
- }
}
/* Load returned vtypes into registers if needed */
guchar *code = p;
int save_mode = SAVE_NONE;
MonoMethod *method = cfg->method;
- MonoType *ret_type = mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret);
+ MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
int i;
switch (ret_type->type) {
guint8 *code;
guint32 code_len;
int i;
+ char *tramp_name;
code = get_delegate_invoke_impl (TRUE, 0, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
+ res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
code = get_delegate_invoke_impl (FALSE, i, &code_len);
- res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
+ tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
+ res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
+ g_free (tramp_name);
}
return res;
return NULL;
/* FIXME: Support more cases */
- if (MONO_TYPE_ISSTRUCT (sig->ret))
+ if (MONO_TYPE_ISSTRUCT (mini_replace_type (sig->ret)))
return NULL;
if (has_target) {
* We need to init this multiple times, since when we are first called, the key might not
* be initialized yet.
*/
- appdomain_tls_offset = mono_domain_get_tls_key ();
- lmf_tls_offset = mono_get_jit_tls_key ();
- lmf_addr_tls_offset = mono_get_jit_tls_key ();
+ jit_tls_offset = mono_get_jit_tls_key ();
/* Only 64 tls entries can be accessed using inline code */
- if (appdomain_tls_offset >= 64)
- appdomain_tls_offset = -1;
- if (lmf_tls_offset >= 64)
- lmf_tls_offset = -1;
- if (lmf_addr_tls_offset >= 64)
- lmf_addr_tls_offset = -1;
+ if (jit_tls_offset >= 64)
+ jit_tls_offset = -1;
#else
#ifdef MONO_XEN_OPT
optimize_for_xen = access ("/proc/xen", F_OK) == 0;
#endif
- appdomain_tls_offset = mono_domain_get_tls_offset ();
- lmf_tls_offset = mono_get_lmf_tls_offset ();
- lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
#endif
}
return 0;
}
-MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
-{
- MonoInst* ins;
-
- if (appdomain_tls_offset == -1)
- return NULL;
-
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->inst_offset = appdomain_tls_offset;
- return ins;
-}
-
#define _CTX_REG(ctx,fld,i) ((&ctx->fld)[i])
mgreg_t
case AMD64_RBP: return ctx->rbp;
case AMD64_RSP: return ctx->rsp;
default:
- if (reg < 8)
- return _CTX_REG (ctx, rax, reg);
- else if (reg >= 12)
- return _CTX_REG (ctx, r12, reg - 12);
- else
- g_assert_not_reached ();
+ return _CTX_REG (ctx, rax, reg);
}
}
ctx->rsp = val;
break;
default:
- if (reg < 8)
- _CTX_REG (ctx, rax, reg) = val;
- else if (reg >= 12)
- _CTX_REG (ctx, r12, reg - 12) = val;
- else
- g_assert_not_reached ();
+ _CTX_REG (ctx, rax, reg) = val;
}
}
return info;
}
+void
+mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
+{
+ ext->lmf.previous_lmf = prev_lmf;
+ /* Mark that this is a MonoLMFExt */
+ ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
+ ext->lmf.rsp = (gssize)ext;
+}
+
#endif