[Mono-dev] ARM PInvoke issue when using long
Paolo Molaro
lupus at ximian.com
Tue Nov 14 13:34:43 EST 2006
On 11/14/06 D M wrote:
> I think the issue is with the mini-arm.c add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple) function.
> It doesn't work properly for MONO_TYPE_I8/MONO_TYPE_R8 if just the first half fits in one register and the other on the stack.
> mono_arch_create_trampoline seems to handle this case.
> Is there an easy fix ?
You may want to try this mostly untested patch.
lupus
--
-----------------------------------------------------------------
lupus at debian.org debian/rules
lupus at ximian.com Monkeys do it better
-------------- next part --------------
Index: inssel-arm.brg
===================================================================
--- inssel-arm.brg (revision 67852)
+++ inssel-arm.brg (working copy)
@@ -274,6 +274,21 @@
stmt: OP_OUTARG_MEMBASE (lreg) {
int offset = tree->backend.arg_info >> 8;
+ int partial = (tree->backend.arg_info & 0xff) == 0xff;
+ if (partial) {
+ MonoCallInst *call = (MonoCallInst*)tree->inst_right;
+ if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+ MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset, state->left->reg1);
+ } else {
+ MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset, state->left->reg2);
+ }
+ tree->opcode = OP_SETREG;
+ tree->dreg = mono_regstate_next_int (s->rs);
+ tree->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN? state->left->reg2: state->left->reg1;
+ mono_bblock_add_inst (s->cbb, tree);
+ mono_call_inst_add_outarg_reg (s, call, tree->dreg, ARMREG_R3, FALSE);
+ return;
+ }
if (G_BYTE_ORDER == G_BIG_ENDIAN) {
MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset, state->left->reg2);
MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset + 4, state->left->reg1);
@@ -286,6 +301,7 @@
stmt: OP_OUTARG_MEMBASE (freg) {
int offset = tree->backend.arg_info >> 8;
if (SOFT_FLOAT_IMPL) {
+ int partial = (tree->backend.arg_info & 0xff) == 0xff;
/* same as OP_OUTARG_MEMBASE (lreg) */
if (G_BYTE_ORDER == G_BIG_ENDIAN) {
MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset, state->left->reg2);
@@ -299,7 +315,17 @@
MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, ARMREG_SP, offset, state->left->reg1);
else if ((tree->backend.arg_info & 0xff) == 4)
MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, ARMREG_SP, offset, state->left->reg1);
- else
+ else if ((tree->backend.arg_info & 0xff) == 0xff) {
+ MonoCallInst *call = (MonoCallInst*)tree->inst_right;
+ int creg;
+ MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, ARMREG_SP, (s->param_area - 8), state->left->reg1);
+ creg = mono_regstate_next_int (s->rs);
+ mono_call_inst_add_outarg_reg (s, call, creg, ARMREG_R3, FALSE);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOAD_MEMBASE, creg, ARMREG_SP, (s->param_area - 8));
+ creg = mono_regstate_next_int (s->rs);
+ MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOAD_MEMBASE, creg, ARMREG_SP, (s->param_area - 4));
+ MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, ARMREG_SP, offset, creg);
+ } else
g_assert_not_reached ();
}
}
Index: mini-arm.c
===================================================================
--- mini-arm.c (revision 67852)
+++ mini-arm.c (working copy)
@@ -318,6 +318,7 @@
enum {
RegTypeGeneral,
RegTypeBase,
+ RegTypeBaseGen,
RegTypeFP,
RegTypeStructByVal,
RegTypeStructByAddr
@@ -355,7 +356,13 @@
ainfo->reg = *gr;
}
} else {
- if (*gr > ARMREG_R2) {
+ if (*gr == ARMREG_R3) {
+ /* first word in r3 and the second on the stack */
+ ainfo->offset = *stack_size;
+ ainfo->reg = ARMREG_SP; /* in the caller */
+ ainfo->regtype = RegTypeBaseGen;
+ *stack_size += 4;
+ } else if (*gr > ARMREG_R3) {
/**stack_size += 7;
*stack_size &= ~7;*/
ainfo->offset = *stack_size;
@@ -820,6 +827,12 @@
} else if (ainfo->regtype == RegTypeBase) {
arg->opcode = OP_OUTARG_MEMBASE;
arg->backend.arg_info = (ainfo->offset << 8) | ainfo->size;
+ } else if (ainfo->regtype == RegTypeBaseGen) {
+ call->used_iregs |= 1 << ARMREG_R3;
+ arg->opcode = OP_OUTARG_MEMBASE;
+ arg->backend.arg_info = (ainfo->offset << 8) | 0xff;
+ if (arg->type == STACK_R8)
+ cfg->flags |= MONO_CFG_HAS_FPOUT;
} else if (ainfo->regtype == RegTypeFP) {
arg->backend.reg3 = ainfo->reg;
/* FP args are passed in int regs */
@@ -2984,6 +2997,12 @@
}
break;
}
+ } else if (ainfo->regtype == 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) {
g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
switch (ainfo->size) {
More information about the Mono-devel-list
mailing list