X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Ftramp-arm-gsharedvt.c;h=4e4334a2e9f580123ec451b73c18e13acba7c0f6;hb=d295ab661864a5dee77a97d298bf2dde09c94de1;hp=f84c5424a14c3c84b5d588868b74aca0738d0979;hpb=58e8a9f85176c9607e605b888ef45db01a0f6997;p=mono.git diff --git a/mono/mini/tramp-arm-gsharedvt.c b/mono/mini/tramp-arm-gsharedvt.c index f84c5424a14..4e4334a2e9f 100644 --- a/mono/mini/tramp-arm-gsharedvt.c +++ b/mono/mini/tramp-arm-gsharedvt.c @@ -1,5 +1,6 @@ -/* - * tramp-arm-gsharedvt.c: gsharedvt support code for arm +/** + * \file + * gsharedvt support code for arm * * Authors: * Zoltan Varga @@ -23,7 +24,6 @@ #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED static inline guint8* @@ -36,9 +36,9 @@ emit_bx (guint8* code, int reg) return code; } - gpointer -mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg) +mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg, + double *caller_fregs, double *callee_fregs) { int i; @@ -54,7 +54,7 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint for (i = 0; i < info->map_count; ++i) { int src = info->map [i * 2]; int dst = info->map [(i * 2) + 1]; - int arg_marshal = (src >> 16) & 0xff; + int arg_marshal = (src >> 24) & 0xff; switch (arg_marshal) { case GSHAREDVT_ARG_NONE: @@ -67,8 +67,8 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint break; case GSHAREDVT_ARG_BYREF_TO_BYVAL: { /* gsharedvt argument passed by value */ - int nslots = (src >> 4) & 0xff; - int src_slot = src & 0xf; + int nslots = (src >> 8) & 0xff; + int src_slot = src & 0xff; int j; gpointer *addr = caller [src_slot]; @@ -77,28 +77,28 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint break; } case GSHAREDVT_ARG_BYREF_TO_BYVAL_I1: { - int src_slot = src & 0xf; + int src_slot = src & 0xff; gpointer *addr = caller [src_slot]; callee [dst] = GINT_TO_POINTER ((int)*(gint8*)addr); break; } case GSHAREDVT_ARG_BYREF_TO_BYVAL_I2: { - int src_slot = src & 0xf; + int src_slot = src & 0xff; gpointer *addr = caller [src_slot]; callee [dst] = GINT_TO_POINTER ((int)*(gint16*)addr); break; } case GSHAREDVT_ARG_BYREF_TO_BYVAL_U1: { - int src_slot = src & 0xf; + int src_slot = src & 0xff; gpointer *addr = caller [src_slot]; callee [dst] = GUINT_TO_POINTER ((guint)*(guint8*)addr); break; } case GSHAREDVT_ARG_BYREF_TO_BYVAL_U2: { - int src_slot = src & 0xf; + int src_slot = src & 0xff; gpointer *addr = caller [src_slot]; callee [dst] = GUINT_TO_POINTER ((guint)*(guint16*)addr); @@ -110,6 +110,66 @@ mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoint } } + /* The slot based approach above is very complicated, use a nested switch instead for fp regs */ + // FIXME: Use this for the other cases as well + if (info->have_fregs) { + CallInfo *caller_cinfo = info->caller_cinfo; + CallInfo *callee_cinfo = info->callee_cinfo; + int aindex; + + for (aindex = 0; aindex < caller_cinfo->nargs; ++aindex) { + ArgInfo *ainfo = &caller_cinfo->args [aindex]; + ArgInfo *ainfo2 = &callee_cinfo->args [aindex]; + + switch (ainfo->storage) { + case RegTypeFP: { + switch (ainfo2->storage) { + case RegTypeFP: + callee_fregs [ainfo2->reg / 2] = caller_fregs [ainfo->reg / 2]; + break; + case RegTypeGSharedVtInReg: + callee [ainfo2->reg] = &caller_fregs [ainfo->reg / 2]; + break; + case RegTypeGSharedVtOnStack: { + int sslot = ainfo2->offset / 4; + callee [sslot + 4] = &caller_fregs [ainfo->reg / 2]; + break; + } + default: + g_assert_not_reached (); + break; + } + break; + } + case RegTypeGSharedVtInReg: { + switch (ainfo2->storage) { + case RegTypeFP: { + callee_fregs [ainfo2->reg / 2] = *(double*)caller [ainfo->reg]; + break; + } + default: + break; + } + break; + } + case RegTypeGSharedVtOnStack: { + switch (ainfo2->storage) { + case RegTypeFP: { + int sslot = ainfo->offset / 4; + callee_fregs [ainfo2->reg / 2] = *(double*)caller [sslot + 4]; + break; + } + default: + break; + } + break; + } + default: + break; + } + } + } + if (info->vcall_offset != -1) { MonoObject *this_obj = caller [0]; @@ -138,10 +198,11 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; guint8 *br_out, *br [16], *br_ret [16]; - int i, arg_reg, npushed, info_offset, mrgctx_offset, caller_reg_area_offset, callee_reg_area_offset; + int i, offset, arg_reg, npushed, info_offset, mrgctx_offset; + int caller_reg_area_offset, caller_freg_area_offset, callee_reg_area_offset, callee_freg_area_offset; int lr_offset, fp, br_ret_index, args_size; - buf_len = 512; + buf_len = 784; buf = code = mono_global_codeman_reserve (buf_len); arg_reg = ARMREG_R0; @@ -160,10 +221,20 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_MOV_REG_REG (code, fp, ARMREG_SP); mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, fp); /* Allocate stack frame */ - ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 32); - info_offset = -4; - mrgctx_offset = -8; - callee_reg_area_offset = - (6 * 4); + ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 32 + (16 * sizeof (double))); + if (MONO_ARCH_FRAME_ALIGNMENT > 8) + ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, (MONO_ARCH_FRAME_ALIGNMENT - 8)); + offset = 4; + info_offset = -offset; + offset += 4; + mrgctx_offset = -offset; + offset += 4 * 4; + callee_reg_area_offset = -offset; + offset += 8 * 8; + caller_freg_area_offset = -offset; + offset += 8 * 8; + callee_freg_area_offset = -offset; + caller_reg_area_offset = cfa_offset - (npushed * sizeof (gpointer)); lr_offset = 4; /* Save info struct which is in r0 */ @@ -173,8 +244,14 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) /* Allocate callee area */ ARM_LDR_IMM (code, ARMREG_IP, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage)); ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP); - /* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */ + /* Allocate callee register area just below the callee area so the slots are correct */ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 4 * sizeof (gpointer)); + if (mono_arm_is_hard_float ()) { + /* Save caller fregs */ + ARM_SUB_REG_IMM8 (code, ARMREG_IP, fp, -caller_freg_area_offset); + for (i = 0; i < 8; ++i) + ARM_FSTD (code, i * 2, ARMREG_IP, (i * sizeof (double))); + } /* * The stack now looks like this: @@ -187,8 +264,8 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) g_assert (mono_arm_thumb_supported ()); /* Call start_gsharedvt_call () */ - /* 4 arguments, needs 0 stack slot, need to clean it up after the call */ - args_size = 0 * sizeof (gpointer); + /* 6 arguments, needs 2 stack slot, need to clean it up after the call */ + args_size = 2 * sizeof (gpointer); ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, args_size); /* arg1 == info */ ARM_LDR_IMM (code, ARMREG_R0, fp, info_offset); @@ -198,6 +275,12 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, args_size); /* arg4 == mrgctx reg */ ARM_LDR_IMM (code, ARMREG_R3, fp, mrgctx_offset); + /* arg5 == caller freg area */ + ARM_SUB_REG_IMM8 (code, ARMREG_IP, fp, -caller_freg_area_offset); + ARM_STR_IMM (code, ARMREG_IP, ARMREG_SP, 0); + /* arg6 == callee freg area */ + ARM_SUB_REG_IMM8 (code, ARMREG_IP, fp, -callee_freg_area_offset); + ARM_STR_IMM (code, ARMREG_IP, ARMREG_SP, 4); /* Make the call */ if (aot) { ji = mono_patch_info_list_prepend (ji, code - buf, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call"); @@ -222,6 +305,12 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_R0); /* Load argument registers */ ARM_LDM (code, ARMREG_SP, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3)); + if (mono_arm_is_hard_float ()) { + /* Load argument fregs */ + ARM_SUB_REG_IMM8 (code, ARMREG_LR, fp, -callee_freg_area_offset); + for (i = 0; i < 8; ++i) + ARM_FLDD (code, i * 2, ARMREG_LR, (i * sizeof (double))); + } /* Pop callee register area */ ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 4 * sizeof (gpointer)); /* Load rgctx */ @@ -285,6 +374,12 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_U2); br [5] = code; ARM_B_COND (code, ARMCOND_EQ, 0); + ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_VFP_R4); + br [6] = code; + ARM_B_COND (code, ARMCOND_EQ, 0); + ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_VFP_R8); + br [7] = code; + ARM_B_COND (code, ARMCOND_EQ, 0); br_ret [br_ret_index ++] = code; ARM_B (code, 0); @@ -319,6 +414,18 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_LDRH_IMM (code, ARMREG_R0, ARMREG_LR, 0); br_ret [br_ret_index ++] = code; ARM_B (code, 0); + /* R4 case */ + arm_patch (br [6], code); + ARM_FLDS (code, ARM_VFP_D0, ARMREG_LR, 0); + code += 4; + br_ret [br_ret_index ++] = code; + ARM_B (code, 0); + /* R8 case */ + arm_patch (br [7], code); + ARM_FLDD (code, ARM_VFP_D0, ARMREG_LR, 0); + code += 4; + br_ret [br_ret_index ++] = code; + ARM_B (code, 0); /* OUT CASE */ arm_patch (br_out, code); @@ -382,6 +489,42 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) ARM_B (code, 0); arm_patch (br [0], code); + ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_VFP_R4); + br [0] = code; + ARM_B_COND (code, ARMCOND_NE, 0); + + /* OUT R4 case */ + /* Load vtype ret addr from the caller arg regs */ + ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset); + ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg)); + ARM_SHL_IMM (code, ARMREG_IP, ARMREG_IP, 2); + ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, fp); + ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, caller_reg_area_offset); + ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 0); + /* Save the return value to the buffer pointed to by the vret addr */ + ARM_FSTS (code, ARM_VFP_D0, ARMREG_IP, 0); + br_ret [br_ret_index ++] = code; + ARM_B (code, 0); + arm_patch (br [0], code); + + ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_VFP_R8); + br [0] = code; + ARM_B_COND (code, ARMCOND_NE, 0); + + /* OUT R8 case */ + /* Load vtype ret addr from the caller arg regs */ + ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset); + ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg)); + ARM_SHL_IMM (code, ARMREG_IP, ARMREG_IP, 2); + ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, fp); + ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, caller_reg_area_offset); + ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 0); + /* Save the return value to the buffer pointed to by the vret addr */ + ARM_FSTD (code, ARM_VFP_D0, ARMREG_IP, 0); + br_ret [br_ret_index ++] = code; + ARM_B (code, 0); + arm_patch (br [0], code); + /* OUT other cases */ br_ret [br_ret_index ++] = code; ARM_B (code, 0);