[Pkg-mono-svn-commits] [mono] 01/01: Merge branch 'armhf' of github.com:alexrp/mono

Jo Shields directhex at moszumanska.debian.org
Tue Dec 3 22:47:36 UTC 2013


This is an automated email from the git hooks/post-receive script.

directhex pushed a commit to branch master-experimental-patches/armhf-support
in repository mono.

commit 17c6b0281a753d368bc3e46f7992e2965fcfd6e0
Author: Alex Rønne Petersen <alexrp at xamarin.com>
Date:   Tue Dec 3 10:04:58 2013 +0100

    Merge branch 'armhf' of github.com:alexrp/mono
    
    (cherry picked from commit b9bcafb382666ccf2f2848065f1760c8f322fa4d)
---
 configure.in                |   8 ++
 mono/mini/exceptions-arm.c  |  20 +--
 mono/mini/mini-arm.c        | 311 ++++++++++++++++++++++++++++++++++++++------
 mono/mini/mini-arm.h        |  43 ++++--
 mono/mini/mini.h            |   4 +
 mono/mini/tramp-arm.c       |  42 ++++--
 mono/utils/mono-hwcap-arm.c |  18 +++
 mono/utils/mono-hwcap-arm.h |   2 +
 8 files changed, 380 insertions(+), 68 deletions(-)

diff --git a/configure.in b/configure.in
index 899fe44..58a3313 100755
--- a/configure.in
+++ b/configure.in
@@ -3071,6 +3071,8 @@ if test ${TARGET} = ARM; then
 		return 0;
 	], [
 		arm_v5=yes
+
+		arm_ver=ARMv5
 	], [])
 
 	AC_TRY_COMPILE([], [
@@ -3081,6 +3083,8 @@ if test ${TARGET} = ARM; then
 	], [
 		arm_v5=yes
 		arm_v6=yes
+
+		arm_ver=ARMv6
 	], [])
 
 	AC_TRY_COMPILE([], [
@@ -3092,8 +3096,12 @@ if test ${TARGET} = ARM; then
 		arm_v5=yes
 		arm_v6=yes
 		arm_v7=yes
+
+		arm_ver=ARMv7
 	], [])
 
+	AC_MSG_RESULT($arm_ver)
+
 	if test x$arm_v5 = xyes; then
 		AC_DEFINE(HAVE_ARMV5, 1, [ARM v5])
 		CPPFLAGS_FOR_LIBGC="$CPPFLAGS_FOR_LIBGC -DHAVE_ARMV5=1"
diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c
index 8931dd8..c124170 100644
--- a/mono/mini/exceptions-arm.c
+++ b/mono/mini/exceptions-arm.c
@@ -60,10 +60,10 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
 
 	ctx_reg = ARMREG_R0;
 
-#if defined(ARM_FPU_VFP)
-	ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, fregs));
-	ARM_FLDMD (code, ARM_VFP_D0, 16, ARMREG_IP);
-#endif
+	if (!mono_arch_is_soft_float ()) {
+		ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, fregs));
+		ARM_FLDMD (code, ARM_VFP_D0, 16, ARMREG_IP);
+	}
 
 	/* move pc to PC */
 	ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, pc));
@@ -220,12 +220,12 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm
 	mono_add_unwind_op_offset (unwind_ops, code, start, ARMREG_LR, - sizeof (mgreg_t));
 
 	/* Save fp regs */
-	ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (double) * 16);
-	cfa_offset += sizeof (double) * 16;
-	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, cfa_offset);
-#if defined(ARM_FPU_VFP)
-	ARM_FSTMD (code, ARM_VFP_D0, 16, ARMREG_SP);
-#endif
+	if (!mono_arch_is_soft_float ()) {
+		ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (double) * 16);
+		cfa_offset += sizeof (double) * 16;
+		mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, cfa_offset);
+		ARM_FSTMD (code, ARM_VFP_D0, 16, ARMREG_SP);
+	}
 
 	/* Param area */
 	ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c
index 544607b..97c5ed3 100644
--- a/mono/mini/mini-arm.c
+++ b/mono/mini/mini-arm.c
@@ -30,11 +30,26 @@
 #error "ARM_FPU_NONE is defined while one of ARM_FPU_VFP/ARM_FPU_VFP_HARD is defined"
 #endif
 
-#if defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
+/*
+ * IS_SOFT_FLOAT: Is full software floating point used?
+ * IS_HARD_FLOAT: Is full hardware floating point used?
+ * IS_VFP: Is hardware floating point with software ABI used?
+ *
+ * These are not necessarily constants, e.g. IS_SOFT_FLOAT and
+ * IS_VFP may delegate to mono_arch_is_soft_float ().
+ */
+
+#if defined(ARM_FPU_VFP_HARD)
+#define IS_SOFT_FLOAT (FALSE)
+#define IS_HARD_FLOAT (TRUE)
+#define IS_VFP (TRUE)
+#elif defined(ARM_FPU_NONE)
 #define IS_SOFT_FLOAT (mono_arch_is_soft_float ())
+#define IS_HARD_FLOAT (FALSE)
 #define IS_VFP (!mono_arch_is_soft_float ())
 #else
 #define IS_SOFT_FLOAT (FALSE)
+#define IS_HARD_FLOAT (FALSE)
 #define IS_VFP (TRUE)
 #endif
 
@@ -105,6 +120,9 @@ static gboolean iphone_abi = FALSE;
  */
 static MonoArmFPU arm_fpu;
 
+static int vfp_scratch1 = ARM_VFP_F28;
+static int vfp_scratch2 = ARM_VFP_F30;
+
 static int i8_align;
 
 static volatile int ss_trigger_var = 0;
@@ -354,7 +372,6 @@ mono_arm_load_jumptable_entry (guint8 *code, gpointer* jte, ARMReg reg)
 }
 #endif
 
-
 static guint8*
 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
 {
@@ -364,10 +381,18 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
 	case OP_FCALL_MEMBASE:
 		if (IS_VFP) {
 			if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4) {
-				ARM_FMSR (code, ins->dreg, ARMREG_R0);
-				ARM_CVTS (code, ins->dreg, ins->dreg);
+				if (IS_HARD_FLOAT) {
+					ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
+				} else {
+					ARM_FMSR (code, ins->dreg, ARMREG_R0);
+					ARM_CVTS (code, ins->dreg, ins->dreg);
+				}
 			} else {
-				ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
+				if (IS_HARD_FLOAT) {
+					ARM_CPYD (code, ins->dreg, ARM_VFP_D0);
+				} else {
+					ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
+				}
 			}
 		}
 		break;
@@ -465,6 +490,37 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
 	return code;
 }
 
+typedef struct {
+	gint32 vreg;
+	gint32 hreg;
+} FloatArgData;
+
+static guint8 *
+emit_float_args (MonoCompile *cfg, MonoCallInst *inst, guint8 *code, int *max_len, guint *offset)
+{
+	GSList *list;
+
+	for (list = inst->float_args; list; list = list->next) {
+		FloatArgData *fad = list->data;
+		MonoInst *var = get_vreg_to_inst (cfg, fad->vreg);
+
+		*max_len += 4;
+
+		if (*offset + *max_len > cfg->code_size) {
+			cfg->code_size += *max_len;
+			cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+
+			code = cfg->native_code + *offset;
+		}
+
+		ARM_FLDS (code, fad->hreg, var->inst_basereg, var->inst_offset);
+
+		*offset = code - cfg->native_code;
+	}
+
+	return code;
+}
+
 /*
  * emit_save_lmf:
  *
@@ -904,6 +960,12 @@ mono_arch_is_soft_float (void)
 }
 #endif
 
+gboolean
+mono_arm_is_hard_float (void)
+{
+	return arm_fpu == MONO_ARM_FPU_VFP_HARD;
+}
+
 static gboolean
 is_regsize_var (MonoGenericSharingContext *gsctx, MonoType *t) {
 	if (t->byref)
@@ -1152,10 +1214,97 @@ add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
 	(*gr) ++;
 }
 
+static void inline
+add_float (guint *fpr, guint *stack_size, ArgInfo *ainfo, gboolean is_double, gint *float_spare)
+{
+	/*
+	 * If we're calling a function like this:
+	 *
+	 * void foo(float a, double b, float c)
+	 *
+	 * We pass a in s0 and b in d1. That leaves us
+	 * with s1 being unused. The armhf ABI recognizes
+	 * this and requires register assignment to then
+	 * use that for the next single-precision arg,
+	 * i.e. c in this example. So float_spare either
+	 * tells us which reg to use for the next single-
+	 * precision arg, or it's -1, meaning use *fpr.
+	 *
+	 * Note that even though most of the JIT speaks
+	 * double-precision, fpr represents single-
+	 * precision registers.
+	 *
+	 * See parts 5.5 and 6.1.2 of the AAPCS for how
+	 * this all works.
+	 */
+
+	if (*fpr < ARM_VFP_F16 || (!is_double && *float_spare >= 0)) {
+		ainfo->storage = RegTypeFP;
+
+		if (is_double) {
+			/*
+			 * If we're passing a double-precision value
+			 * and *fpr is odd (e.g. it's s1, s3, ...)
+			 * we need to use the next even register. So
+			 * we mark the current *fpr as a spare that
+			 * can be used for the next single-precision
+			 * value.
+			 */
+			if (*fpr % 2) {
+				*float_spare = *fpr;
+				(*fpr)++;
+			}
+
+			/*
+			 * At this point, we have an even register
+			 * so we assign that and move along.
+			 */
+			ainfo->reg = *fpr;
+			*fpr += 2;
+		} else if (*float_spare >= 0) {
+			/*
+			 * We're passing a single-precision value
+			 * and it looks like a spare single-
+			 * precision register is available. Let's
+			 * use it.
+			 */
+
+			ainfo->reg = *float_spare;
+			*float_spare = -1;
+		} else {
+			/*
+			 * If we hit this branch, we're passing a
+			 * single-precision value and we can simply
+			 * use the next available register.
+			 */
+
+			ainfo->reg = *fpr;
+			(*fpr)++;
+		}
+	} else {
+		/*
+		 * We've exhausted available floating point
+		 * regs, so pass the rest on the stack.
+		 */
+
+		if (is_double) {
+			*stack_size += 7;
+			*stack_size &= ~7;
+		}
+
+		ainfo->offset = *stack_size;
+		ainfo->reg = ARMREG_SP;
+		ainfo->storage = RegTypeBase;
+
+		*stack_size += 8;
+	}
+}
+
 static CallInfo*
 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
 {
-	guint i, gr, pstart;
+	guint i, gr, fpr, pstart;
+	gint float_spare;
 	int n = sig->hasthis + sig->param_count;
 	MonoType *simpletype;
 	guint32 stack_size = 0;
@@ -1170,6 +1319,8 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 
 	cinfo->nargs = n;
 	gr = ARMREG_R0;
+	fpr = ARM_VFP_F0;
+	float_spare = -1;
 
 	t = mini_type_get_underlying_type (gsctx, sig->ret);
 	if (MONO_TYPE_ISSTRUCT (t)) {
@@ -1222,6 +1373,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 			/* Prevent implicit arguments and sig_cookie from
 			   being passed in registers */
 			gr = ARMREG_R3 + 1;
+			fpr = ARM_VFP_F16;
 			/* Emit the signature cookie just before the implicit arguments */
 			add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
 		}
@@ -1263,7 +1415,6 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 		case MONO_TYPE_STRING:
 		case MONO_TYPE_SZARRAY:
 		case MONO_TYPE_ARRAY:
-		case MONO_TYPE_R4:
 			cinfo->args [n].size = sizeof (gpointer);
 			add_general (&gr, &stack_size, ainfo, TRUE);
 			n++;
@@ -1344,11 +1495,30 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 		}
 		case MONO_TYPE_U8:
 		case MONO_TYPE_I8:
-		case MONO_TYPE_R8:
 			ainfo->size = 8;
 			add_general (&gr, &stack_size, ainfo, FALSE);
 			n++;
 			break;
+		case MONO_TYPE_R4:
+			ainfo->size = 4;
+
+			if (IS_HARD_FLOAT)
+				add_float (&fpr, &stack_size, ainfo, FALSE, &float_spare);
+			else
+				add_general (&gr, &stack_size, ainfo, TRUE);
+
+			n++;
+			break;
+		case MONO_TYPE_R8:
+			ainfo->size = 8;
+
+			if (IS_HARD_FLOAT)
+				add_float (&fpr, &stack_size, ainfo, TRUE, &float_spare);
+			else
+				add_general (&gr, &stack_size, ainfo, FALSE);
+
+			n++;
+			break;
 		case MONO_TYPE_VAR:
 		case MONO_TYPE_MVAR:
 			/* gsharedvt arguments are passed by ref */
@@ -1376,6 +1546,7 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 		/* Prevent implicit arguments and sig_cookie from
 		   being passed in registers */
 		gr = ARMREG_R3 + 1;
+		fpr = ARM_VFP_F16;
 		/* Emit the signature cookie just before the implicit arguments */
 		add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
 	}
@@ -1411,9 +1582,13 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
 		case MONO_TYPE_R4:
 		case MONO_TYPE_R8:
 			cinfo->ret.storage = RegTypeFP;
-			cinfo->ret.reg = ARMREG_R0;
-			/* FIXME: cinfo->ret.reg = ???;
-			cinfo->ret.storage = RegTypeFP;*/
+
+			if (IS_HARD_FLOAT) {
+				cinfo->ret.reg = ARM_VFP_F0;
+			} else {
+				cinfo->ret.reg = ARMREG_R0;
+			}
+
 			break;
 		case MONO_TYPE_GENERICINST:
 			if (!mono_type_generic_inst_is_valuetype (simpletype)) {
@@ -2104,19 +2279,50 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 			}
 			break;
 		case RegTypeFP: {
-			/* FIXME: */
-			NOT_IMPLEMENTED;
-#if 0
-			arg->backend.reg3 = ainfo->reg;
-			/* FP args are passed in int regs */
-			call->used_iregs |= 1 << ainfo->reg;
+			int fdreg = mono_alloc_freg (cfg);
+
 			if (ainfo->size == 8) {
-				arg->opcode = OP_OUTARG_R8;
-				call->used_iregs |= 1 << (ainfo->reg + 1);
+				MONO_INST_NEW (cfg, ins, OP_FMOVE);
+				ins->sreg1 = in->dreg;
+				ins->dreg = fdreg;
+				MONO_ADD_INS (cfg->cbb, ins);
+
+				mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
 			} else {
-				arg->opcode = OP_OUTARG_R4;
+				FloatArgData *fad;
+
+				/*
+				 * Mono's register allocator doesn't speak single-precision registers that
+				 * overlap double-precision registers (i.e. armhf). So we have to work around
+				 * the register allocator and load the value from memory manually.
+				 *
+				 * So we create a variable for the float argument and an instruction to store
+				 * the argument into the variable. We then store the list of these arguments
+				 * in cfg->float_args. This list is then used by emit_float_args later to
+				 * pass the arguments in the various call opcodes.
+				 *
+				 * This is not very nice, and we should really try to fix the allocator.
+				 */
+
+				MonoInst *float_arg = mono_compile_create_var (cfg, &mono_defaults.single_class->byval_arg, OP_LOCAL);
+
+				/* Make sure the instruction isn't seen as pointless and removed.
+				 */
+				float_arg->flags |= MONO_INST_VOLATILE;
+
+				MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, float_arg->dreg, in->dreg);
+
+				/* We use the dreg to look up the instruction later. The hreg is used to
+				 * emit the instruction that loads the value into the FP reg.
+				 */
+				fad = mono_mempool_alloc0 (cfg->mempool, sizeof (FloatArgData));
+				fad->vreg = float_arg->dreg;
+				fad->hreg = ainfo->reg;
+
+				call->float_args = g_slist_append_mempool (cfg->mempool, call->float_args, fad);
 			}
-#endif
+
+			call->used_iregs |= 1 << ainfo->reg;
 			cfg->flags |= MONO_CFG_HAS_FPOUT;
 			break;
 		}
@@ -2238,6 +2444,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
 			}
 			break;
 		case MONO_ARM_FPU_VFP:
+		case MONO_ARM_FPU_VFP_HARD:
 			if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
 				MonoInst *ins;
 
@@ -3209,10 +3416,10 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
 	/* sreg is a float, dreg is an integer reg  */
 	if (IS_VFP) {
 		if (is_signed)
-			ARM_TOSIZD (code, ARM_VFP_F0, sreg);
+			ARM_TOSIZD (code, vfp_scratch1, sreg);
 		else
-			ARM_TOUIZD (code, ARM_VFP_F0, sreg);
-		ARM_FMRS (code, dreg, ARM_VFP_F0);
+			ARM_TOUIZD (code, vfp_scratch1, sreg);
+		ARM_FMRS (code, dreg, vfp_scratch1);
 	}
 	if (!is_signed) {
 		if (size == 1)
@@ -4364,6 +4571,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 		case OP_VOIDCALL:
 		case OP_CALL:
 			call = (MonoCallInst*)ins;
+
+			if (IS_HARD_FLOAT)
+				code = emit_float_args (cfg, call, code, &max_len, &offset);
+
 			if (ins->flags & MONO_INST_HAS_METHOD)
 				mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
 			else
@@ -4379,6 +4590,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 		case OP_VCALL2_REG:
 		case OP_VOIDCALL_REG:
 		case OP_CALL_REG:
+			if (IS_HARD_FLOAT)
+				code = emit_float_args (cfg, (MonoCallInst *)ins, code, &max_len, &offset);
+
 			code = emit_call_reg (code, ins->sreg1);
 			ins->flags |= MONO_INST_GC_CALLSITE;
 			ins->backend.pc_offset = code - cfg->native_code;
@@ -4394,6 +4608,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
 			g_assert (ins->sreg1 != ARMREG_LR);
 			call = (MonoCallInst*)ins;
+
+			if (IS_HARD_FLOAT)
+				code = emit_float_args (cfg, call, code, &max_len, &offset);
+
 			if (call->dynamic_imt_arg || call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
 				imt_arg = TRUE;
 			if (!arm_is_imm12 (ins->inst_offset))
@@ -4770,34 +4988,41 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 			break;
 		case OP_STORER4_MEMBASE_REG:
 			g_assert (arm_is_fpimm8 (ins->inst_offset));
-			ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
-			ARM_FSTS (code, ARM_VFP_F0, ins->inst_destbasereg, ins->inst_offset);
+			ARM_CVTD (code, vfp_scratch1, ins->sreg1);
+			ARM_FSTS (code, vfp_scratch1, ins->inst_destbasereg, ins->inst_offset);
 			break;
 		case OP_LOADR4_MEMBASE:
 			g_assert (arm_is_fpimm8 (ins->inst_offset));
-			ARM_FLDS (code, ARM_VFP_F0, ins->inst_basereg, ins->inst_offset);
-			ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
+			ARM_FLDS (code, vfp_scratch1, ins->inst_basereg, ins->inst_offset);
+			ARM_CVTS (code, ins->dreg, vfp_scratch1);
 			break;
 		case OP_ICONV_TO_R_UN: {
 			g_assert_not_reached ();
 			break;
 		}
 		case OP_ICONV_TO_R4:
-			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);
+			ARM_FMSR (code, vfp_scratch1, ins->sreg1);
+			ARM_FSITOS (code, vfp_scratch1, vfp_scratch1);
+			ARM_CVTS (code, ins->dreg, vfp_scratch1);
 			break;
 		case OP_ICONV_TO_R8:
-			ARM_FMSR (code, ARM_VFP_F0, ins->sreg1);
-			ARM_FSITOD (code, ins->dreg, ARM_VFP_F0);
+			ARM_FMSR (code, vfp_scratch1, ins->sreg1);
+			ARM_FSITOD (code, ins->dreg, vfp_scratch1);
 			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);
+
+				if (!IS_HARD_FLOAT) {
+					ARM_FMRS (code, ARMREG_R0, ARM_VFP_F0);
+				}
 			} else {
-				ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
+				if (IS_HARD_FLOAT) {
+					ARM_CPYD (code, ARM_VFP_D0, ins->sreg1);
+				} else {
+					ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
+				}
 			}
 			break;
 		case OP_FCONV_TO_I1:
@@ -4975,18 +5200,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 					jte [0] = GUINT_TO_POINTER (0xffffffff);
 					jte [1] = GUINT_TO_POINTER (0x7fefffff);
 					code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
-					ARM_FLDD (code, ARM_VFP_D0, ARMREG_IP, 0);
+					ARM_FLDD (code, vfp_scratch1, ARMREG_IP, 0);
 				}
 #else
-				ARM_ABSD (code, ARM_VFP_D1, ins->sreg1);
-				ARM_FLDD (code, ARM_VFP_D0, ARMREG_PC, 0);
+				ARM_ABSD (code, vfp_scratch2, ins->sreg1);
+				ARM_FLDD (code, vfp_scratch1, ARMREG_PC, 0);
 				ARM_B (code, 1);
 				*(guint32*)code = 0xffffffff;
 				code += 4;
 				*(guint32*)code = 0x7fefffff;
 				code += 4;
 #endif
-				ARM_CMPD (code, ARM_VFP_D1, ARM_VFP_D0);
+				ARM_CMPD (code, vfp_scratch2, vfp_scratch1);
 				ARM_FMSTAT (code);
 				EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
 				ARM_CMPD (code, ins->sreg1, ins->sreg1);
@@ -5456,7 +5681,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 					break;
 				}
 			} else if (ainfo->storage == RegTypeFP) {
-				g_assert_not_reached ();
+				code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
+				ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
+
+				if (ainfo->size == 8)
+					ARM_FSTD (code, ainfo->reg, ARMREG_IP, 0);
+				else
+					ARM_FSTS (code, ainfo->reg, ARMREG_IP, 0);
 			} else if (ainfo->storage == RegTypeStructByVal) {
 				int doffset = inst->inst_offset;
 				int soffset = 0;
diff --git a/mono/mini/mini-arm.h b/mono/mini/mini-arm.h
index 93a256b..c1f21f8 100644
--- a/mono/mini/mini-arm.h
+++ b/mono/mini/mini-arm.h
@@ -19,10 +19,6 @@
 #define MONO_ARCH_SOFT_FLOAT_FALLBACK 1
 #endif
 
-#ifdef ARM_FPU_VFP_HARD
-#error "hardfp-abi not yet supported."
-#endif
-
 #if defined(__ARM_EABI__)
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 #define ARM_ARCHITECTURE "armel"
@@ -56,10 +52,9 @@
 #endif
 
 #define MONO_MAX_IREGS 16
-#define MONO_MAX_FREGS 16
+#define MONO_MAX_FREGS 32
 
 #define MONO_SAVED_GREGS 10 /* r4-r11, ip, lr */
-#define MONO_SAVED_FREGS 8
 
 /* r4-r11, ip, lr: registers saved in the LMF  */
 #define MONO_ARM_REGSAVE_MASK 0x5ff0
@@ -71,9 +66,32 @@
 #define MONO_ARCH_CALLEE_REGS ((1<<ARMREG_R0) | (1<<ARMREG_R1) | (1<<ARMREG_R2) | (1<<ARMREG_R3) | (1<<ARMREG_IP))
 #define MONO_ARCH_CALLEE_SAVED_REGS ((1<<ARMREG_V1) | (1<<ARMREG_V2) | (1<<ARMREG_V3) | (1<<ARMREG_V4) | (1<<ARMREG_V5) | (1<<ARMREG_V6) | (1<<ARMREG_V7))
 
-/* Every double precision vfp register, d0/d1 is reserved for a scratch reg */
-#define MONO_ARCH_CALLEE_FREGS 0x55555550
-#define MONO_ARCH_CALLEE_SAVED_FREGS 0
+/*
+ * TODO: Make use of VFP v3 registers d16-d31.
+ */
+
+/*
+ * TODO: We can't use registers d8-d15 in hard float mode because the
+ * register allocator doesn't allocate floating point registers globally.
+ */
+
+#if defined(ARM_FPU_VFP_HARD)
+#define MONO_SAVED_FREGS 16
+/*
+ * d8-d15 must be preserved across function calls. We use d14-d15 as
+ * scratch registers in the JIT. The rest have no meaning tied to them.
+ */
+#define MONO_ARCH_CALLEE_FREGS 0x00005555
+#define MONO_ARCH_CALLEE_SAVED_FREGS 0x55550000
+#else
+#define MONO_SAVED_FREGS 0
+/*
+ * No registers need to be preserved across function calls. We use d14-d15
+ * as scratch registers in the JIT. The rest have no meaning tied to them.
+ */
+#define MONO_ARCH_CALLEE_FREGS 0x05555555
+#define MONO_ARCH_CALLEE_SAVED_FREGS 0x00000000
+#endif
 
 #define MONO_ARCH_USE_FPSTACK FALSE
 #define MONO_ARCH_FPSTACK_SIZE 0
@@ -164,6 +182,10 @@ struct MonoLMF {
 	mgreg_t    sp;
 	mgreg_t    ip;
 	mgreg_t    fp;
+	/* Currently only used in trampolines on armhf to hold d0-d15. We don't really
+	 * need to put d0-d7 in the LMF, but it simplifies the trampoline code.
+	 */
+	double     fregs [16];
 	/* all but sp and pc: matches the PUSH instruction layout in the trampolines
 	 * 0-4 should be considered undefined (execpt in the magic tramp)
 	 * sp is saved at IP.
@@ -291,4 +313,7 @@ guint8*
 mono_arm_load_jumptable_entry (guint8 *code, gpointer *jte, ARMReg reg) MONO_INTERNAL;
 #endif
 
+gboolean
+mono_arm_is_hard_float (void) MONO_INTERNAL;
+
 #endif /* __MONO_MINI_ARM_H__ */
diff --git a/mono/mini/mini.h b/mono/mini/mini.h
index a99aa42..16f58a2 100644
--- a/mono/mini/mini.h
+++ b/mono/mini/mini.h
@@ -846,6 +846,10 @@ struct MonoCallInst {
 	LLVMCallInfo *cinfo;
 	int rgctx_arg_reg, imt_arg_reg;
 #endif
+#ifdef TARGET_ARM
+	/* See the comment in mini-arm.c!mono_arch_emit_call for RegTypeFP. */
+	GSList *float_args;
+#endif
 };
 
 struct MonoCallArgParm {
diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c
index 39070e6..35e4eb9 100644
--- a/mono/mini/tramp-arm.c
+++ b/mono/mini/tramp-arm.c
@@ -16,6 +16,7 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/arch/arm/arm-codegen.h>
+#include <mono/arch/arm/arm-vfp-codegen.h>
 
 #include "mini.h"
 #include "mini-arm.h"
@@ -179,7 +180,7 @@ emit_bx (guint8* code, int reg)
 	return code;
 }
 
-/* Stack size for trampoline function 
+/* Stack size for trampoline function
  */
 #define STACK ALIGN_TO (sizeof (MonoLMF), 8)
 
@@ -201,7 +202,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	gpointer *constants;
 #endif
 
-	int cfa_offset, lmf_offset, regsave_size, lr_offset;
+	int cfa_offset, regsave_size, lr_offset;
 	GSList *unwind_ops = NULL;
 	MonoJumpInfo *ji = NULL;
 	int buf_len;
@@ -213,7 +214,12 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	/* Now we'll create in 'buf' the ARM trampoline code. This
 	 is the trampoline code common to all methods  */
 
-	buf_len = 212;
+	buf_len = 272;
+
+	/* Add space for saving/restoring VFP regs. */
+	if (mono_arm_is_hard_float ())
+		buf_len += 8 * 2;
+
 	code = buf = mono_global_codeman_reserve (buf_len);
 
 	/*
@@ -222,8 +228,6 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	 * saved as sp + LR_OFFSET by the push in the specific trampoline
 	 */
 
-	/* The offset of lmf inside the stack frame */
-	lmf_offset = STACK - sizeof (MonoLMF);
 	/* The size of the area already allocated by the push in the specific trampoline */
 	regsave_size = 14 * sizeof (mgreg_t);
 	/* The offset where lr was saved inside the regsave area */
@@ -288,11 +292,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	 * The pointer to the struct is put in r1.
 	 * the iregs array is already allocated on the stack by push.
 	 */
-	ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, STACK - regsave_size);
+	code = mono_arm_emit_load_imm (code, ARMREG_R2, STACK - regsave_size);
+	ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_R2);
 	cfa_offset += STACK - regsave_size;
 	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
 	/* V1 == lmf */
-	ARM_ADD_REG_IMM8 (code, ARMREG_V1, ARMREG_SP, STACK - sizeof (MonoLMF));
+	code = mono_arm_emit_load_imm (code, ARMREG_R2, STACK - sizeof (MonoLMF));
+	ARM_ADD_REG_REG (code, ARMREG_V1, ARMREG_SP, ARMREG_R2);
 
 	/*
 	 * The stack now looks like:
@@ -316,7 +322,8 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 		ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, method));
 	}
 	/* save caller SP */
-	ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, cfa_offset);
+	code = mono_arm_emit_load_imm (code, ARMREG_R2, cfa_offset);
+	ARM_ADD_REG_REG (code, ARMREG_R2, ARMREG_SP, ARMREG_R2);
 	ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, sp));
 	/* save caller FP */
 	ARM_LDR_IMM (code, ARMREG_R2, ARMREG_V1, (G_STRUCT_OFFSET (MonoLMF, iregs) + ARMREG_FP*4));
@@ -329,11 +336,22 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	}
 	ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, ip));
 
+	/* Save VFP registers. */
+	if (mono_arm_is_hard_float ()) {
+		/*
+		 * Strictly speaking, we don't have to save d0-d7 in the LMF, but
+		 * it's easier than attempting to store them on the stack since
+		 * this trampoline code is pretty messy.
+		 */
+		ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, fregs));
+		ARM_FSTMD (code, ARM_VFP_D0, 8, ARMREG_R0);
+	}
+
 	/*
 	 * Now we're ready to call xxx_trampoline ().
 	 */
 	/* Arg 1: the saved registers */
-	ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, iregs));
+	ARM_ADD_REG_IMM (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, iregs), 0);
 
 	/* Arg 2: code (next address to the instruction that called us) */
 	if (tramp_type == MONO_TRAMPOLINE_JUMP) {
@@ -413,6 +431,12 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
 	/* *(lmf_addr) = previous_lmf */
 	ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
 
+	/* Restore VFP registers. */
+	if (mono_arm_is_hard_float ()) {
+		ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, fregs));
+		ARM_FLDMD (code, ARM_VFP_D0, 8, ARMREG_R0);
+	}
+
 	/* Non-standard function epilogue. Instead of doing a proper
 	 * return, we just jump to the compiled code.
 	 */
diff --git a/mono/utils/mono-hwcap-arm.c b/mono/utils/mono-hwcap-arm.c
index d5d5f00..e87635b 100644
--- a/mono/utils/mono-hwcap-arm.c
+++ b/mono/utils/mono-hwcap-arm.c
@@ -35,6 +35,8 @@ gboolean mono_hwcap_arm_is_v6 = FALSE;
 gboolean mono_hwcap_arm_is_v7 = FALSE;
 gboolean mono_hwcap_arm_is_v7s = FALSE;
 gboolean mono_hwcap_arm_has_vfp = FALSE;
+gboolean mono_hwcap_arm_has_vfp3 = FALSE;
+gboolean mono_hwcap_arm_has_vfp3_d16 = FALSE;
 gboolean mono_hwcap_arm_has_thumb = FALSE;
 gboolean mono_hwcap_arm_has_thumb2 = FALSE;
 
@@ -60,6 +62,14 @@ mono_hwcap_arch_init (void)
 		if (hwcap & 0x00000064)
 			mono_hwcap_arm_has_vfp = TRUE;
 
+		/* HWCAP_ARM_VFPv3 */
+		if (hwcap & 0x00002000)
+			mono_hwcap_arm_has_vfp3 = TRUE;
+
+		/* HWCAP_ARM_VFPv3D16 */
+		if (hwcap & 0x00004000)
+			mono_hwcap_arm_has_vfp3_d16 = TRUE;
+
 		/* TODO: Find a way to detect Thumb 2. */
 	}
 
@@ -136,6 +146,12 @@ mono_hwcap_arch_init (void)
 				if (strstr (line, "vfp"))
 					mono_hwcap_arm_has_vfp = TRUE;
 
+				if (strstr (line, "vfpv3"))
+					mono_hwcap_arm_has_vfp3 = TRUE;
+
+				if (strstr (line, "vfpv3-d16"))
+					mono_hwcap_arm_has_vfp3_d16 = TRUE;
+
 				continue;
 			}
 		}
@@ -154,6 +170,8 @@ mono_hwcap_print(FILE *f)
 	g_fprintf (f, "mono_hwcap_arm_is_v7 = %i\n", mono_hwcap_arm_is_v7);
 	g_fprintf (f, "mono_hwcap_arm_is_v7s = %i\n", mono_hwcap_arm_is_v7s);
 	g_fprintf (f, "mono_hwcap_arm_has_vfp = %i\n", mono_hwcap_arm_has_vfp);
+	g_fprintf (f, "mono_hwcap_arm_has_vfp3 = %i\n", mono_hwcap_arm_has_vfp3);
+	g_fprintf (f, "mono_hwcap_arm_has_vfp3_d16 = %i\n", mono_hwcap_arm_has_vfp3_d16);
 	g_fprintf (f, "mono_hwcap_arm_has_thumb = %i\n", mono_hwcap_arm_has_thumb);
 	g_fprintf (f, "mono_hwcap_arm_has_thumb2 = %i\n", mono_hwcap_arm_has_thumb2);
 }
diff --git a/mono/utils/mono-hwcap-arm.h b/mono/utils/mono-hwcap-arm.h
index 6bc9c3b..76a20a1 100644
--- a/mono/utils/mono-hwcap-arm.h
+++ b/mono/utils/mono-hwcap-arm.h
@@ -8,6 +8,8 @@ extern gboolean mono_hwcap_arm_is_v6;
 extern gboolean mono_hwcap_arm_is_v7;
 extern gboolean mono_hwcap_arm_is_v7s;
 extern gboolean mono_hwcap_arm_has_vfp;
+extern gboolean mono_hwcap_arm_has_vfp3;
+extern gboolean mono_hwcap_arm_has_vfp3_d16;
 extern gboolean mono_hwcap_arm_has_thumb;
 extern gboolean mono_hwcap_arm_has_thumb2;
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mono/packages/mono.git



More information about the Pkg-mono-svn-commits mailing list