#ifdef ARM_FPU_FPA
if (ins->dreg != ARM_FPA_F0)
ARM_MVFD (code, ins->dreg, ARM_FPA_F0);
+#elif defined(ARM_FPU_VFP)
+ if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4) {
+ ARM_FMSR (code, ins->dreg, ARMREG_R0);
+ ARM_CVTS (code, ins->dreg, ins->dreg);
+ } else {
+ ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
+ }
#endif
break;
}
return NULL;
}
-gpointer*
-mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
+#define MAX_ARCH_DELEGATE_PARAMS 3
+
+static gpointer
+get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
{
- gpointer vt;
- int displacement;
- vt = mono_arch_get_vcall_slot (code, regs, &displacement);
- if (!vt)
- return NULL;
- return (gpointer*)((char*)vt + displacement);
+ guint8 *code, *start;
+
+ if (has_target) {
+ start = code = mono_global_codeman_reserve (12);
+
+ /* Replace the this argument with the target */
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, target));
+ ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
+
+ g_assert ((code - start) <= 12);
+
+ mono_arch_flush_icache (start, 12);
+ } else {
+ int size, i;
+
+ size = 8 + param_count * 4;
+ start = code = mono_global_codeman_reserve (size);
+
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ /* slide down the arguments */
+ for (i = 0; i < param_count; ++i) {
+ ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
+ }
+ ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
+
+ g_assert ((code - start) <= size);
+
+ mono_arch_flush_icache (start, size);
+ }
+
+ if (code_size)
+ *code_size = code - start;
+
+ return start;
}
-#define MAX_ARCH_DELEGATE_PARAMS 3
+/*
+ * mono_arch_get_delegate_invoke_impls:
+ *
+ * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
+ * trampolines.
+ */
+GSList*
+mono_arch_get_delegate_invoke_impls (void)
+{
+ GSList *res = NULL;
+ guint8 *code;
+ guint32 code_len;
+ int i;
+
+ code = get_delegate_invoke_impl (TRUE, 0, &code_len);
+ res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len));
+
+ for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ code = get_delegate_invoke_impl (FALSE, i, &code_len);
+ res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len));
+ }
+
+ return res;
+}
gpointer
mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
mono_mini_arch_unlock ();
return cached;
}
-
- start = code = mono_global_codeman_reserve (12);
-
- /* Replace the this argument with the target */
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
- ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, target));
- ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
-
- g_assert ((code - start) <= 12);
- mono_arch_flush_icache (start, 12);
+ if (mono_aot_only)
+ start = mono_aot_get_named_code ("delegate_invoke_impl_has_target");
+ else
+ start = get_delegate_invoke_impl (TRUE, 0, NULL);
cached = start;
mono_mini_arch_unlock ();
return cached;
} else {
static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
- int size, i;
+ int i;
if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
return NULL;
return code;
}
- size = 8 + sig->param_count * 4;
- start = code = mono_global_codeman_reserve (size);
-
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
- /* slide down the arguments */
- for (i = 0; i < sig->param_count; ++i) {
- ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
+ if (mono_aot_only) {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
+ start = mono_aot_get_named_code (name);
+ g_free (name);
+ } else {
+ start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
}
- ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
-
- g_assert ((code - start) <= size);
-
- mono_arch_flush_icache (start, size);
cache [sig->param_count] = start;
mono_mini_arch_unlock ();
return start;
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
return;
}
+#elif defined(ARM_FPU_VFP)
+ if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
+ MonoInst *ins;
+
+ MONO_INST_NEW (cfg, ins, OP_SETFRET);
+ ins->dreg = cfg->ret->dreg;
+ ins->sreg1 = val->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return;
+ }
#else
if (ret->type == MONO_TYPE_R4 || ret->type == MONO_TYPE_R8) {
MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
bb->max_vreg = cfg->next_vreg;
}
+void
+mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
+{
+ MonoInst *ins;
+ int vreg;
+
+ if (long_ins->opcode == OP_LNEG) {
+ ins = long_ins;
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
+ NULLIFY_INS (ins);
+ }
+}
+
static guchar*
emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
{
pdata.found = 0;
mono_domain_lock (domain);
- mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
+ mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
if (!pdata.found) {
/* this uses the first available slot */
pdata.found = 2;
- mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
+ mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
}
mono_domain_unlock (domain);
code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
- ARM_B (code, 0);
+ if (cfg->compile_aot) {
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+ ARM_B (code, 0);
+ *(gpointer*)code = NULL;
+ code += 4;
+ ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
+ } else {
+ ARM_B (code, 0);
+ }
break;
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
/* This is generated by the local regalloc pass which runs after the lowering pass */
if (!arm_is_fpimm8 (ins->inst_offset)) {
code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
ARM_STFD (code, ins->sreg1, ARMREG_LR, 0);
} else {
ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
/* This is generated by the local regalloc pass which runs after the lowering pass */
if (!arm_is_fpimm8 (ins->inst_offset)) {
code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
} else {
ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
case OP_ICONV_TO_R8:
ARM_FLTD (code, ins->dreg, ins->sreg1);
break;
+
#elif defined(ARM_FPU_VFP)
+
case OP_R8CONST:
if (cfg->compile_aot) {
ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
}
break;
case OP_STORER8_MEMBASE_REG:
- g_assert (arm_is_fpimm8 (ins->inst_offset));
- ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+ /* This is generated by the local regalloc pass which runs after the lowering pass */
+ if (!arm_is_fpimm8 (ins->inst_offset)) {
+ code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
+ ARM_FSTD (code, ins->sreg1, ARMREG_LR, 0);
+ } else {
+ ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+ }
break;
case OP_LOADR8_MEMBASE:
- g_assert (arm_is_fpimm8 (ins->inst_offset));
- ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+ /* This is generated by the local regalloc pass which runs after the lowering pass */
+ if (!arm_is_fpimm8 (ins->inst_offset)) {
+ code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
+ ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
+ } else {
+ ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+ }
break;
case OP_STORER4_MEMBASE_REG:
g_assert (arm_is_fpimm8 (ins->inst_offset));
- ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
+ ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
+ ARM_FSTS (code, ARM_VFP_F0, ins->inst_destbasereg, ins->inst_offset);
break;
case OP_LOADR4_MEMBASE:
g_assert (arm_is_fpimm8 (ins->inst_offset));
- ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
+ ARM_FLDS (code, ARM_VFP_F0, ins->inst_basereg, ins->inst_offset);
+ ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
break;
case OP_ICONV_TO_R_UN: {
g_assert_not_reached ();
break;
}
case OP_ICONV_TO_R4:
- g_assert_not_reached ();
- //ARM_FLTS (code, ins->dreg, ins->sreg1);
+ ARM_FMSR (code, ARM_VFP_F0, ins->sreg1);
+ ARM_FSITOS (code, ARM_VFP_F0, ARM_VFP_F0);
+ ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
break;
case OP_ICONV_TO_R8:
- g_assert_not_reached ();
- //ARM_FLTD (code, ins->dreg, ins->sreg1);
+ ARM_FMSR (code, ARM_VFP_F0, ins->sreg1);
+ ARM_FSITOD (code, ins->dreg, ARM_VFP_F0);
break;
+
+ case OP_SETFRET:
+ if (mono_method_signature (cfg->method)->ret->type == MONO_TYPE_R4) {
+ ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
+ ARM_FMRS (code, ARMREG_R0, ARM_VFP_F0);
+ } else {
+ ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
+ }
+ break;
+
#endif
+
case OP_FCONV_TO_I1:
code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
break;
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg1, ins->sreg2);
+ ARM_FMSTAT (code);
#endif
break;
case OP_FCEQ:
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg1, ins->sreg2);
+ ARM_FMSTAT (code);
#endif
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg1, ins->sreg2);
+ ARM_FMSTAT (code);
#endif
ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg1, ins->sreg2);
+ ARM_FMSTAT (code);
#endif
ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg2, ins->sreg1);
+ ARM_FMSTAT (code);
#endif
ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
#elif defined(ARM_FPU_VFP)
ARM_CMPD (code, ins->sreg2, ins->sreg1);
+ ARM_FMSTAT (code);
#endif
ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
#ifdef ARM_FPU_FPA
if (ins->dreg != ins->sreg1)
ARM_MVFD (code, ins->dreg, ins->sreg1);
-#else
- g_assert_not_reached ();
+#elif defined(ARM_FPU_VFP)
+ ARM_CPYD (code, ins->dreg, ins->sreg1);
#endif
break;
}
CallInfo *cinfo;
int tracing = 0;
int lmf_offset = 0;
- int prev_sp_offset;
+ int prev_sp_offset, reg_offset;
if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
tracing = 1;
cfg->code_size = 256 + sig->param_count * 20;
code = cfg->native_code = g_malloc (cfg->code_size);
+ mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
+
ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
alloc_size = cfg->stack_offset;
pos = 0;
if (!method->save_lmf) {
- // FIXME: Why save IP ?
+ /* We save SP by storing it into IP and saving IP */
ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
prev_sp_offset = 8; /* ip and lr */
for (i = 0; i < 16; ++i) {
if (cfg->used_int_regs & (1 << i))
prev_sp_offset += 4;
}
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
+ reg_offset = 0;
+ for (i = 0; i < 16; ++i) {
+ if ((cfg->used_int_regs & (1 << i)) || (i == ARMREG_IP) || (i == ARMREG_LR)) {
+ mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
+ reg_offset += 4;
+ }
+ }
} else {
ARM_PUSH (code, 0x5ff0);
prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
+ reg_offset = 0;
+ for (i = 0; i < 16; ++i) {
+ if ((i > ARMREG_R3) && (i != ARMREG_SP) && (i != ARMREG_PC)) {
+ mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
+ reg_offset += 4;
+ }
+ }
pos += sizeof (MonoLMF) - prev_sp_offset;
lmf_offset = pos;
}
code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
}
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset + alloc_size);
}
if (cfg->frame_reg != ARMREG_SP) {
ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
+ mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
}
//g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
prev_sp_offset += alloc_size;
void
mono_arch_fixup_jinfo (MonoCompile *cfg)
{
- /* max encoded stack usage is 64KB * 4 */
- g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
- cfg->jit_info->used_regs |= cfg->stack_usage << 14;
}
#ifdef MONO_ARCH_HAVE_IMT
size = BASE_SIZE;
constant_pool_starts = g_new0 (guint32*, count);
- g_assert (!fail_tramp);
+ /*
+ * We might be called with a fail_tramp from the IMT builder code even if
+ * MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK is not defined.
+ */
+ //g_assert (!fail_tramp);
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
if (large_offsets)
size += 4 * count; /* The ARM_ADD_REG_IMM to pop the stack */
- start = code = mono_code_manager_reserve (domain->code_mp, size);
+ start = code = mono_domain_code_reserve (domain, size);
#if DEBUG_IMT
printf ("building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable);