[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