Skip to content

Commit

Permalink
[jit] Fix the return of vtypes containing a single fp member from pin…
Browse files Browse the repository at this point in the history
…voke methods on osx/x86. Fixes #23813.
  • Loading branch information
vargaz committed Oct 15, 2014
1 parent a9f31e6 commit 727f8fe
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 5 deletions.
17 changes: 12 additions & 5 deletions mono/mini/decompose.c
Expand Up @@ -1330,18 +1330,18 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
if (call->vret_in_reg) {
MonoCallInst *call2;

/* Replace the vcall with an integer call */
/* Replace the vcall with a scalar call */
MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
memcpy (call2, call, sizeof (MonoCallInst));
switch (ins->opcode) {
case OP_VCALL:
call2->inst.opcode = OP_CALL;
call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
break;
case OP_VCALL_REG:
call2->inst.opcode = OP_CALL_REG;
call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
break;
case OP_VCALL_MEMBASE:
call2->inst.opcode = OP_CALL_MEMBASE;
call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
break;
}
call2->inst.dreg = alloc_preg (cfg);
Expand All @@ -1367,12 +1367,19 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
break;
case 3:
case 4:
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
if (call->vret_in_reg_fp)
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
else
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
break;
case 5:
case 6:
case 7:
case 8:
if (call->vret_in_reg_fp) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
break;
}
#if SIZEOF_REGISTER == 4
/*
FIXME Other ABIs might return in different regs than the ones used for LCALL.
Expand Down
4 changes: 4 additions & 0 deletions mono/mini/mini-x86.c
Expand Up @@ -1440,6 +1440,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
* result there.
*/
call->vret_in_reg = TRUE;
#if defined(__APPLE__)
if (cinfo->ret.pair_storage [0] == ArgOnDoubleFpStack || cinfo->ret.pair_storage [0] == ArgOnFloatFpStack)
call->vret_in_reg_fp = TRUE;
#endif
if (call->vret_var)
NULLIFY_INS (call->vret_var);
}
Expand Down
2 changes: 2 additions & 0 deletions mono/mini/mini.h
Expand Up @@ -851,6 +851,8 @@ struct MonoCallInst {
* calling convention as OP_CALL.
*/
guint vret_in_reg : 1;
/* Whenever vret_in_reg returns fp values */
guint vret_in_reg_fp : 1;
/* Whenever there is an IMT argument and it is dynamic */
guint dynamic_imt_arg : 1;
/* Whenever there is an RGCTX argument */
Expand Down
14 changes: 14 additions & 0 deletions mono/tests/libtest.c
Expand Up @@ -5313,6 +5313,20 @@ mono_test_marshal_return_lpwstr (void)
return res;
}

typedef struct {
double d;
} SingleDoubleStruct;

LIBTEST_API SingleDoubleStruct STDCALL
mono_test_marshal_return_single_double_struct (void)
{
SingleDoubleStruct res;

res.d = 3.0;

return res;
}


#ifndef TARGET_X86

Expand Down
16 changes: 16 additions & 0 deletions mono/tests/pinvoke2.cs
Expand Up @@ -71,6 +71,11 @@ public struct DelegateStruct {
public SimpleDelegate del3;
}

[StructLayout (LayoutKind.Sequential)]
public struct SingleDoubleStruct {
public double d;
}

/* sparcv9 has complex conventions when passing structs with doubles in them
by value, some simple tests for them */
[StructLayout (LayoutKind.Sequential)]
Expand Down Expand Up @@ -1800,5 +1805,16 @@ public static int test_0_native_thiscall ()

return 0;
}

[DllImport ("libtest", EntryPoint = "mono_test_marshal_return_single_double_struct")]
public static extern SingleDoubleStruct mono_test_marshal_return_single_double_struct ();

public static int test_0_x86_single_double_struct_ret () {
double d = mono_test_marshal_return_single_double_struct ().d;
if (d != 3.0)
return 1;
else
return 0;
}
}

0 comments on commit 727f8fe

Please sign in to comment.