#define ADD_LR_PC_4 ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 25) | (1 << 23) | (ARMREG_PC << 16) | (ARMREG_LR << 12) | 4)
#define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) | (ARMREG_LR << 12) | ARMREG_PC)
#define DEBUG_IMT 0
+
+/* A variant of ARM_LDR_IMM which can handle large offsets */
+#define ARM_LDR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \
+ if (arm_is_imm12 ((offset))) { \
+ ARM_LDR_IMM (code, (dreg), (basereg), (offset)); \
+ } else { \
+ g_assert ((scratch_reg) != (basereg)); \
+ code = mono_arm_emit_load_imm (code, (scratch_reg), (offset)); \
+ ARM_LDR_REG_REG (code, (dreg), (basereg), (scratch_reg)); \
+ } \
+ } while (0)
+
+#define ARM_STR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \
+ if (arm_is_imm12 ((offset))) { \
+ ARM_STR_IMM (code, (dreg), (basereg), (offset)); \
+ } else { \
+ g_assert ((scratch_reg) != (basereg)); \
+ code = mono_arm_emit_load_imm (code, (scratch_reg), (offset)); \
+ ARM_STR_REG_REG (code, (dreg), (basereg), (scratch_reg)); \
+ } \
+ } while (0)
const char*
mono_arch_regname (int reg)
return "unknown";
}
+#ifndef DISABLE_JIT
+
static guint8*
emit_big_add (guint8 *code, int dreg, int sreg, int imm)
{
return code;
}
+#endif /* #ifndef DISABLE_JIT */
+
/*
* mono_arch_get_argument_info:
* @csig: a method signature
mono_arch_cpu_optimizazions (guint32 *exclude_mask)
{
guint32 opts = 0;
+ const char *cpu_arch = getenv ("MONO_CPU_ARCH");
+ if (cpu_arch != NULL) {
+ thumb_supported = strstr (cpu_arch, "thumb") != NULL;
+ if (strncmp (cpu_arch, "armv", 4) == 0) {
+ v5_supported = cpu_arch [4] >= '5';
+ v7_supported = cpu_arch [4] >= '7';
+ }
+ } else {
#if __APPLE__
thumb_supported = TRUE;
v5_supported = TRUE;
/*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
}
#endif
+ }
/* no arm-specific optimizations yet */
*exclude_mask = 0;
return opts;
}
+#ifndef DISABLE_JIT
+
static gboolean
is_regsize_var (MonoType *t) {
if (t->byref)
return 2;
}
+#endif /* #ifndef DISABLE_JIT */
+
#ifndef __GNUC_PREREQ
#define __GNUC_PREREQ(maj, min) (0)
#endif
#endif
}
-enum {
+typedef enum {
RegTypeNone,
RegTypeGeneral,
RegTypeIRegPair,
RegTypeFP,
RegTypeStructByVal,
RegTypeStructByAddr
-};
+} ArgStorage;
typedef struct {
gint32 offset;
guint16 vtsize; /* in param area */
guint8 reg;
- guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
+ ArgStorage storage;
guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
} ArgInfo;
if (*gr > ARMREG_R3) {
ainfo->offset = *stack_size;
ainfo->reg = ARMREG_SP; /* in the caller */
- ainfo->regtype = RegTypeBase;
+ ainfo->storage = RegTypeBase;
*stack_size += 4;
} else {
- ainfo->regtype = RegTypeGeneral;
+ ainfo->storage = RegTypeGeneral;
ainfo->reg = *gr;
}
} else {
/* first word in r3 and the second on the stack */
ainfo->offset = *stack_size;
ainfo->reg = ARMREG_SP; /* in the caller */
- ainfo->regtype = RegTypeBaseGen;
+ ainfo->storage = RegTypeBaseGen;
*stack_size += 4;
} else if (*gr >= ARMREG_R3) {
#ifdef __ARM_EABI__
#endif
ainfo->offset = *stack_size;
ainfo->reg = ARMREG_SP; /* in the caller */
- ainfo->regtype = RegTypeBase;
+ ainfo->storage = RegTypeBase;
*stack_size += 8;
} else {
#ifdef __ARM_EABI__
if (i8_align == 8 && ((*gr) & 1))
(*gr) ++;
#endif
- ainfo->regtype = RegTypeIRegPair;
+ ainfo->storage = RegTypeIRegPair;
ainfo->reg = *gr;
}
(*gr) ++;
}
static CallInfo*
-get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
{
guint i, gr;
int n = sig->hasthis + sig->param_count;
MonoType *simpletype;
guint32 stack_size = 0;
- CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
+ CallInfo *cinfo;
+
+ if (mp)
+ cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
+ else
+ cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
cinfo->nargs = n;
gr = ARMREG_R0;
/* FIXME: handle returning a struct */
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
- add_general (&gr, &stack_size, &cinfo->ret, TRUE);
- cinfo->struct_ret = ARMREG_R0;
- cinfo->vtype_retaddr = TRUE;
+ guint32 align;
+
+ if (is_pinvoke && mono_class_native_size (mono_class_from_mono_type (sig->ret), &align) <= sizeof (gpointer)) {
+ cinfo->ret.storage = RegTypeStructByVal;
+ } else {
+ add_general (&gr, &stack_size, &cinfo->ret, TRUE);
+ cinfo->struct_ret = ARMREG_R0;
+ cinfo->vtype_retaddr = TRUE;
+ }
}
n = 0;
DEBUG(printf("params: %d\n", sig->param_count));
for (i = 0; i < sig->param_count; ++i) {
if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
- /* Prevent implicit arguments and sig_cookie from
+ /* Prevent implicit arguments and sig_cookie from
being passed in registers */
- gr = ARMREG_R3 + 1;
- /* Emit the signature cookie just before the implicit arguments */
- add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
- }
- DEBUG(printf("param %d: ", i));
+ gr = ARMREG_R3 + 1;
+ /* Emit the signature cookie just before the implicit arguments */
+ add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
+ }
+ DEBUG(printf("param %d: ", i));
if (sig->params [i]->byref) {
DEBUG(printf("byref\n"));
add_general (&gr, &stack_size, cinfo->args + n, TRUE);
n++;
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+ if (!mono_type_generic_inst_is_valuetype (simpletype)) {
cinfo->args [n].size = sizeof (gpointer);
add_general (&gr, &stack_size, cinfo->args + n, TRUE);
n++;
align_size += (sizeof (gpointer) - 1);
align_size &= ~(sizeof (gpointer) - 1);
nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
- cinfo->args [n].regtype = RegTypeStructByVal;
+ cinfo->args [n].storage = RegTypeStructByVal;
/* FIXME: align stack_size if needed */
#ifdef __ARM_EABI__
if (align >= 8 && (gr & 1))
}
}
+ /* Handle the case where there are no implicit arguments */
+ if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+ /* Prevent implicit arguments and sig_cookie from
+ being passed in registers */
+ gr = ARMREG_R3 + 1;
+ /* Emit the signature cookie just before the implicit arguments */
+ add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
+ }
+
{
simpletype = mini_type_get_underlying_type (NULL, sig->ret);
switch (simpletype->type) {
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
case MONO_TYPE_STRING:
- cinfo->ret.regtype = RegTypeGeneral;
+ cinfo->ret.storage = RegTypeGeneral;
cinfo->ret.reg = ARMREG_R0;
break;
case MONO_TYPE_U8:
case MONO_TYPE_I8:
- cinfo->ret.regtype = RegTypeIRegPair;
+ cinfo->ret.storage = RegTypeIRegPair;
cinfo->ret.reg = ARMREG_R0;
break;
case MONO_TYPE_R4:
case MONO_TYPE_R8:
- cinfo->ret.regtype = RegTypeFP;
+ cinfo->ret.storage = RegTypeFP;
cinfo->ret.reg = ARMREG_R0;
/* FIXME: cinfo->ret.reg = ???;
- cinfo->ret.regtype = RegTypeFP;*/
+ cinfo->ret.storage = RegTypeFP;*/
break;
case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
- cinfo->ret.regtype = RegTypeGeneral;
+ if (!mono_type_generic_inst_is_valuetype (simpletype)) {
+ cinfo->ret.storage = RegTypeGeneral;
cinfo->ret.reg = ARMREG_R0;
break;
}
- cinfo->ret.regtype = RegTypeStructByAddr;
- break;
+ /* Fall through */
case MONO_TYPE_VALUETYPE:
- cinfo->ret.regtype = RegTypeStructByAddr;
- break;
case MONO_TYPE_TYPEDBYREF:
- cinfo->ret.regtype = RegTypeStructByAddr;
+ if (cinfo->ret.storage != RegTypeStructByVal)
+ cinfo->ret.storage = RegTypeStructByAddr;
break;
case MONO_TYPE_VOID:
break;
return cinfo;
}
+#ifndef DISABLE_JIT
/*
* Set var information according to the calling convention. arm version.
{
MonoMethodSignature *sig;
MonoMethodHeader *header;
- MonoInst *inst;
+ MonoInst *ins;
int i, offset, size, align, curinst;
int frame_reg = ARMREG_FP;
+ CallInfo *cinfo;
+ guint32 ualign;
+
+ sig = mono_method_signature (cfg->method);
+
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
+ cinfo = cfg->arch.cinfo;
/* FIXME: this will change when we use FP as gcc does */
cfg->flags |= MONO_CFG_HAS_SPILLUP;
if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
- header = mono_method_get_header (cfg->method);
+ header = cfg->header;
/*
* We use the frame register also for any method that has
/* V5 is reserved for passing the vtable/rgctx/IMT method */
cfg->used_int_regs |= (1 << ARMREG_V5);
- sig = mono_method_signature (cfg->method);
-
offset = 0;
curinst = 0;
if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
- /* FIXME: handle long and FP values */
switch (mini_type_get_underlying_type (NULL, sig->ret)->type) {
case MONO_TYPE_VOID:
break;
offset += 8;
/* the MonoLMF structure is stored just below the stack pointer */
-
- if (sig->call_convention == MONO_CALL_VARARG) {
- cfg->sig_cookie = 0;
- }
-
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
- inst = cfg->vret_addr;
- offset += sizeof(gpointer) - 1;
- offset &= ~(sizeof(gpointer) - 1);
- inst->inst_offset = offset;
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
- if (G_UNLIKELY (cfg->verbose_level > 1)) {
- printf ("vret_addr =");
- mono_print_ins (cfg->vret_addr);
+ if (cinfo->ret.storage == RegTypeStructByVal) {
+ cfg->ret->opcode = OP_REGOFFSET;
+ cfg->ret->inst_basereg = cfg->frame_reg;
+ offset += sizeof (gpointer) - 1;
+ offset &= ~(sizeof (gpointer) - 1);
+ cfg->ret->inst_offset = - offset;
+ } else {
+ ins = cfg->vret_addr;
+ offset += sizeof(gpointer) - 1;
+ offset &= ~(sizeof(gpointer) - 1);
+ ins->inst_offset = offset;
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = frame_reg;
+ if (G_UNLIKELY (cfg->verbose_level > 1)) {
+ printf ("vret_addr =");
+ mono_print_ins (cfg->vret_addr);
+ }
}
offset += sizeof(gpointer);
- if (sig->call_convention == MONO_CALL_VARARG)
- cfg->sig_cookie += sizeof (gpointer);
+ }
+
+ /* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
+ if (cfg->arch.seq_point_info_var) {
+ MonoInst *ins;
+
+ ins = cfg->arch.seq_point_info_var;
+
+ size = 4;
+ align = 4;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = frame_reg;
+ ins->inst_offset = offset;
+ offset += size;
+
+ ins = cfg->arch.ss_trigger_page_var;
+ size = 4;
+ align = 4;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = frame_reg;
+ ins->inst_offset = offset;
+ offset += size;
}
curinst = cfg->locals_start;
for (i = curinst; i < cfg->num_varinfo; ++i) {
- inst = cfg->varinfo [i];
- if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
+ ins = cfg->varinfo [i];
+ if ((ins->flags & MONO_INST_IS_DEAD) || ins->opcode == OP_REGVAR || ins->opcode == OP_REGOFFSET)
continue;
/* inst->backend.is_pinvoke indicates native sized value types, this is used by the
* pinvoke wrappers when they call functions returning structure */
- if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
- guint32 ualign;
- size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &ualign);
+ if (ins->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (ins->inst_vtype) && ins->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
+ size = mono_class_native_size (mono_class_from_mono_type (ins->inst_vtype), &ualign);
align = ualign;
}
else
- size = mono_type_size (inst->inst_vtype, &align);
+ size = mono_type_size (ins->inst_vtype, &align);
/* FIXME: if a structure is misaligned, our memcpy doesn't work,
* since it loads/stores misaligned words, which don't do the right thing.
align = 4;
offset += align - 1;
offset &= ~(align - 1);
- inst->inst_offset = offset;
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_offset = offset;
+ ins->inst_basereg = frame_reg;
offset += size;
//g_print ("allocating local %d to %d\n", i, inst->inst_offset);
}
curinst = 0;
if (sig->hasthis) {
- inst = cfg->args [curinst];
- if (inst->opcode != OP_REGVAR) {
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
+ ins = cfg->args [curinst];
+ if (ins->opcode != OP_REGVAR) {
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = frame_reg;
offset += sizeof (gpointer) - 1;
offset &= ~(sizeof (gpointer) - 1);
- inst->inst_offset = offset;
+ ins->inst_offset = offset;
offset += sizeof (gpointer);
- if (sig->call_convention == MONO_CALL_VARARG)
- cfg->sig_cookie += sizeof (gpointer);
}
curinst++;
}
+ if (sig->call_convention == MONO_CALL_VARARG) {
+ size = 4;
+ align = 4;
+
+ /* Allocate a local slot to hold the sig cookie address */
+ offset += align - 1;
+ offset &= ~(align - 1);
+ cfg->sig_cookie = offset;
+ offset += size;
+ }
+
for (i = 0; i < sig->param_count; ++i) {
- inst = cfg->args [curinst];
- if (inst->opcode != OP_REGVAR) {
- inst->opcode = OP_REGOFFSET;
- inst->inst_basereg = frame_reg;
- size = mono_type_size (sig->params [i], &align);
+ ins = cfg->args [curinst];
+
+ if (ins->opcode != OP_REGVAR) {
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = frame_reg;
+ size = mini_type_stack_size_full (NULL, sig->params [i], &ualign, sig->pinvoke);
+ align = ualign;
/* FIXME: if a structure is misaligned, our memcpy doesn't work,
* since it loads/stores misaligned words, which don't do the right thing.
*/
align = 4;
offset += align - 1;
offset &= ~(align - 1);
- inst->inst_offset = offset;
+ ins->inst_offset = offset;
offset += size;
- if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
- cfg->sig_cookie += size;
}
curinst++;
}
mono_arch_create_vars (MonoCompile *cfg)
{
MonoMethodSignature *sig;
+ CallInfo *cinfo;
sig = mono_method_signature (cfg->method);
- if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
+ cinfo = cfg->arch.cinfo;
+
+ if (cinfo->ret.storage == RegTypeStructByVal)
+ cfg->ret_var_is_local = TRUE;
+
+ if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != RegTypeStructByVal) {
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 = ");
}
}
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+ MonoMethodSignature *tmp_sig;
+ MonoInst *sig_arg;
+
+ if (call->tail_call)
+ NOT_IMPLEMENTED;
+
+ /* FIXME: Add support for signature tokens to AOT */
+ cfg->disable_aot = TRUE;
+
+ g_assert (cinfo->sig_cookie.storage == RegTypeBase);
+
+ /*
+ * mono_ArgIterator_Setup assumes the signature cookie is
+ * passed first and all the arguments which were before it are
+ * passed on the stack after the signature. So compensate by
+ * passing a different signature.
+ */
+ tmp_sig = mono_metadata_signature_dup (call->signature);
+ tmp_sig->param_count -= call->signature->sentinelpos;
+ tmp_sig->sentinelpos = 0;
+ memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
+
+ MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
+ sig_arg->dreg = mono_alloc_ireg (cfg);
+ sig_arg->inst_p0 = tmp_sig;
+ MONO_ADD_INS (cfg->cbb, sig_arg);
+
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_arg->dreg);
+}
+
+#ifdef ENABLE_LLVM
+LLVMCallInfo*
+mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
+{
+ int i, n;
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ LLVMCallInfo *linfo;
+
+ n = sig->param_count + sig->hasthis;
+
+ cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
+
+ linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
+
+ /*
+ * LLVM always uses the native ABI while we use our own ABI, the
+ * only difference is the handling of vtypes:
+ * - we only pass/receive them in registers in some cases, and only
+ * in 1 or 2 integer registers.
+ */
+ if (cinfo->ret.storage != RegTypeGeneral && cinfo->ret.storage != RegTypeNone && cinfo->ret.storage != RegTypeFP && cinfo->ret.storage != RegTypeIRegPair) {
+ cfg->exception_message = g_strdup ("unknown ret conv");
+ cfg->disable_llvm = TRUE;
+ return linfo;
+ }
+
+ for (i = 0; i < n; ++i) {
+ ainfo = cinfo->args + i;
+
+ linfo->args [i].storage = LLVMArgNone;
+
+ switch (ainfo->storage) {
+ case RegTypeGeneral:
+ case RegTypeIRegPair:
+ case RegTypeBase:
+ linfo->args [i].storage = LLVMArgInIReg;
+ break;
+ default:
+ cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
+ cfg->disable_llvm = TRUE;
+ break;
+ }
+ }
+
+ return linfo;
+}
+#endif
+
void
mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
{
sig = call->signature;
n = sig->param_count + sig->hasthis;
- cinfo = get_call_info (sig, sig->pinvoke);
+ cinfo = get_call_info (NULL, sig, sig->pinvoke);
for (i = 0; i < n; ++i) {
ArgInfo *ainfo = cinfo->args + i;
t = mini_type_get_underlying_type (NULL, t);
if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
- /* FIXME: */
- NOT_IMPLEMENTED;
+ /* Emit the signature cookie just before the implicit arguments */
+ emit_sig_cookie (cfg, call, cinfo);
}
in = call->args [i];
- switch (ainfo->regtype) {
+ switch (ainfo->storage) {
case RegTypeGeneral:
case RegTypeIRegPair:
if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
}
}
+ /* Handle the case where there are no implicit arguments */
+ 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)) {
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);
+ if (cinfo->ret.storage == RegTypeStructByVal) {
+ /* The JIT will transform this into a normal call */
+ call->vret_in_reg = TRUE;
+ } else {
+ 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->ret.reg, FALSE);
+ mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
+ }
}
call->stack_usage = cinfo->stack_usage;
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);
+ if (COMPILE_LLVM (cfg)) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_SETLRET);
+ ins->sreg1 = val->dreg + 1;
+ ins->sreg2 = val->dreg + 2;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
return;
}
#ifdef MONO_ARCH_SOFT_FLOAT
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
}
+#endif /* #ifndef DISABLE_JIT */
+
gboolean
mono_arch_is_inst_imm (gint64 imm)
{
if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
return FALSE;
- switch (cinfo->ret.regtype) {
+ switch (cinfo->ret.storage) {
case RegTypeNone:
case RegTypeGeneral:
case RegTypeIRegPair:
}
for (i = 0; i < cinfo->nargs; ++i) {
- switch (cinfo->args [i].regtype) {
+ switch (cinfo->args [i].storage) {
case RegTypeGeneral:
break;
case RegTypeIRegPair:
ArchDynCallInfo *info;
CallInfo *cinfo;
- cinfo = get_call_info (sig, FALSE);
+ cinfo = get_call_info (NULL, sig, FALSE);
if (!dyn_call_supported (cinfo, sig)) {
g_free (cinfo);
ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
int slot = -1;
- if (ainfo->regtype == RegTypeGeneral || ainfo->regtype == RegTypeIRegPair || ainfo->regtype == RegTypeStructByVal)
+ if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
slot = ainfo->reg;
- else if (ainfo->regtype == RegTypeBase)
+ else if (ainfo->storage == RegTypeBase)
slot = PARAM_REGS + (ainfo->offset / 4);
else
g_assert_not_reached ();
/* Fall though */
}
case MONO_TYPE_VALUETYPE:
- g_assert (ainfo->regtype == RegTypeStructByVal);
+ g_assert (ainfo->storage == RegTypeStructByVal);
if (ainfo->size == 0)
slot = PARAM_REGS + (ainfo->offset / 4);
}
}
+#ifndef DISABLE_JIT
+
/*
* Allow tracing to work with this interface (with an optional argument)
*/
gboolean swap = FALSE;
int reg;
+ if (!ins->next) {
+ /* Optimized away */
+ NULLIFY_INS (ins);
+ break;
+ }
+
/* Some fp compares require swapped operands */
- g_assert (ins->next);
switch (ins->next->opcode) {
case OP_FBGT:
ins->next->opcode = OP_FBLT;
return code;
}
+#endif /* #ifndef DISABLE_JIT */
+
typedef struct {
guchar *code;
const guchar *target;
return code;
}
+gboolean
+mono_arm_thumb_supported (void)
+{
+ return thumb_supported;
+}
+
+#ifndef DISABLE_JIT
+
/*
* emit_load_volatile_arguments:
*
pos = 0;
- cinfo = get_call_info (sig, sig->pinvoke);
+ cinfo = get_call_info (NULL, sig, sig->pinvoke);
if (MONO_TYPE_ISSTRUCT (sig->ret)) {
ArgInfo *ainfo = &cinfo->ret;
inst = cfg->args [pos];
if (cfg->verbose_level > 2)
- g_print ("Loading argument %d (type: %d)\n", i, ainfo->regtype);
+ g_print ("Loading argument %d (type: %d)\n", i, ainfo->storage);
if (inst->opcode == OP_REGVAR) {
- if (ainfo->regtype == RegTypeGeneral)
+ if (ainfo->storage == RegTypeGeneral)
ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
- else if (ainfo->regtype == RegTypeFP) {
+ else if (ainfo->storage == RegTypeFP) {
g_assert_not_reached ();
- } else if (ainfo->regtype == RegTypeBase) {
+ } else if (ainfo->storage == RegTypeBase) {
// FIXME:
NOT_IMPLEMENTED;
/*
} else
g_assert_not_reached ();
} else {
- if (ainfo->regtype == RegTypeGeneral || ainfo->regtype == RegTypeIRegPair) {
+ if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair) {
switch (ainfo->size) {
case 1:
case 2:
}
break;
}
- } else if (ainfo->regtype == RegTypeBaseGen) {
+ } else if (ainfo->storage == RegTypeBaseGen) {
// FIXME:
NOT_IMPLEMENTED;
- } else if (ainfo->regtype == RegTypeBase) {
+ } else if (ainfo->storage == RegTypeBase) {
/* Nothing to do */
- } else if (ainfo->regtype == RegTypeFP) {
+ } else if (ainfo->storage == RegTypeFP) {
g_assert_not_reached ();
- } else if (ainfo->regtype == RegTypeStructByVal) {
+ } else if (ainfo->storage == RegTypeStructByVal) {
int doffset = inst->inst_offset;
int soffset = 0;
int cur_reg;
if (ainfo->vtsize)
// FIXME:
NOT_IMPLEMENTED;
- } else if (ainfo->regtype == RegTypeStructByAddr) {
+ } else if (ainfo->storage == RegTypeStructByAddr) {
} else {
// FIXME:
NOT_IMPLEMENTED;
return code;
}
-#ifndef DISABLE_JIT
-
void
mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
{
case OP_NOT_NULL:
break;
case OP_SEQ_POINT: {
- int i, il_offset;
+ int i;
MonoInst *info_var = cfg->arch.seq_point_info_var;
MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
MonoInst *var;
ARM_LDR_IMM (code, dreg, dreg, 0);
}
- il_offset = ins->inst_imm;
-
- if (!cfg->seq_points)
- cfg->seq_points = g_ptr_array_new ();
- g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
- g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
+ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
if (cfg->compile_aot) {
guint32 offset = code - cfg->native_code;
ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
break;
case OP_ARGLIST: {
-#if ARM_PORT
- if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
- ppc_addi (code, ppc_r11, 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_stw (code, ppc_r11, 0, ins->sreg1);
-#endif
+ g_assert (cfg->sig_cookie < 128);
+ ARM_LDR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
+ ARM_STR_IMM (code, ARMREG_IP, ins->sreg1, 0);
break;
}
case OP_FCALL:
case OP_CALL_HANDLER:
mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
ARM_BL (code, 0);
+ mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
break;
case OP_LABEL:
ins->inst_c0 = code - cfg->native_code;
mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE);
+#ifndef MONO_CROSS_COMPILE
#ifdef HAVE_AEABI_READ_TP
mono_register_jit_icall (__aeabi_read_tp, "__aeabi_read_tp", mono_create_icall_signature ("void"), TRUE);
#endif
+#endif
}
#define patch_lis_ori(ip,val) do {\
}
}
+#ifndef DISABLE_JIT
+
/*
* Stack frame layout:
*
/* load arguments allocated to register from the stack */
pos = 0;
- cinfo = get_call_info (sig, sig->pinvoke);
+ cinfo = get_call_info (NULL, sig, sig->pinvoke);
- if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != RegTypeStructByVal) {
ArgInfo *ainfo = &cinfo->ret;
inst = cfg->vret_addr;
g_assert (arm_is_imm12 (inst->inst_offset));
ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
}
+
+ if (sig->call_convention == MONO_CALL_VARARG) {
+ ArgInfo *cookie = &cinfo->sig_cookie;
+
+ /* Save the sig cookie address */
+ g_assert (cookie->storage == RegTypeBase);
+
+ g_assert (arm_is_imm12 (prev_sp_offset + cookie->offset));
+ g_assert (arm_is_imm12 (cfg->sig_cookie));
+ ARM_ADD_REG_IMM8 (code, ARMREG_IP, cfg->frame_reg, prev_sp_offset + cookie->offset);
+ ARM_STR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
+ }
+
for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
ArgInfo *ainfo = cinfo->args + i;
inst = cfg->args [pos];
if (cfg->verbose_level > 2)
- g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
+ g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
if (inst->opcode == OP_REGVAR) {
- if (ainfo->regtype == RegTypeGeneral)
+ if (ainfo->storage == RegTypeGeneral)
ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
- else if (ainfo->regtype == RegTypeFP) {
+ else if (ainfo->storage == RegTypeFP) {
g_assert_not_reached ();
- } else if (ainfo->regtype == RegTypeBase) {
+ } else if (ainfo->storage == RegTypeBase) {
if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
} else {
g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
} else {
/* the argument should be put on the stack: FIXME handle size != word */
- if (ainfo->regtype == RegTypeGeneral || ainfo->regtype == RegTypeIRegPair) {
+ if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair) {
switch (ainfo->size) {
case 1:
if (arm_is_imm12 (inst->inst_offset))
}
break;
}
- } else if (ainfo->regtype == RegTypeBaseGen) {
+ } else if (ainfo->storage == RegTypeBaseGen) {
g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
g_assert (arm_is_imm12 (inst->inst_offset));
ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
- } else if (ainfo->regtype == RegTypeBase) {
+ } else if (ainfo->storage == RegTypeBase) {
if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
} else {
}
break;
}
- } else if (ainfo->regtype == RegTypeFP) {
+ } else if (ainfo->storage == RegTypeFP) {
g_assert_not_reached ();
- } else if (ainfo->regtype == RegTypeStructByVal) {
+ } else if (ainfo->storage == RegTypeStructByVal) {
int doffset = inst->inst_offset;
int soffset = 0;
int cur_reg;
//g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
}
- } else if (ainfo->regtype == RegTypeStructByAddr) {
+ } else if (ainfo->storage == RegTypeStructByAddr) {
g_assert_not_reached ();
/* FIXME: handle overrun! with struct sizes not multiple of 4 */
code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
int pos, i, rot_amount;
int max_epilog_size = 16 + 20*4;
guint8 *code;
+ CallInfo *cinfo;
if (cfg->method->save_lmf)
max_epilog_size += 128;
}
pos = 0;
+ /* Load returned vtypes into registers if needed */
+ cinfo = cfg->arch.cinfo;
+ if (cinfo->ret.storage == RegTypeStructByVal) {
+ MonoInst *ins = cfg->ret;
+
+ if (arm_is_imm12 (ins->inst_offset)) {
+ ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
+ } else {
+ code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
+ }
+ }
+
if (method->save_lmf) {
int lmf_offset;
/* all but r0-r3, sp and pc */
}
+#endif /* #ifndef DISABLE_JIT */
+
static gboolean tls_offset_inited = FALSE;
void
#ifdef MONO_ARCH_HAVE_IMT
+#ifndef DISABLE_JIT
+
void
mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
{
}
}
+#endif /* DISABLE_JIT */
+
MonoMethod*
mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
{
return (MonoMethod*) code_ptr [1];
}
-MonoObject*
-mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
-{
- return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), regs, NULL);
-}
-
MonoVTable*
mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
{