This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch] libffi darwin structure implementation (PPC)
- From: Andreas Tobler <toa at pop dot agri dot ch>
- To: David Edelsohn <dje at watson dot ibm dot com>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>, Geoff Keating <geoffk at geoffk dot org>,Anthony Green <green at redhat dot com>
- Date: Thu, 04 Sep 2003 17:11:15 +0200
- Subject: Re: [patch] libffi darwin structure implementation (PPC)
- References: <200309020221.WAA20408@makai.watson.ibm.com>
Hi all,
Here a reworked diff.
I took the suggestions from Andrew and the ones from David.
I hope it is better now.
Tested with the just commited framework :)
What does apple say ?
Thanks for review.
Andreas
2003-09-04 Andreas Tobler <a.tobler@schweiz.ch>
* src/prep_cif.c (initialize_aggregate): Don't use rounded size
of ffi_arg for PowerPC Darwin.
* src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures
according to the OS-X ABI. Split AIX FFI_STRUCT case.
(ffi_prep_cif_machdep): Likewise.
(ffi_closure_helper_DARWIN): Likewise.
(ffi_prep_clousure): Change the branch statement. Avoid the
casts on lvalues.
Index: src/prep_cif.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/prep_cif.c,v
retrieving revision 1.5
diff -u -r1.5 prep_cif.c
--- src/prep_cif.c 30 Sep 2002 11:59:42 -0000 1.5
+++ src/prep_cif.c 4 Sep 2003 15:08:20 -0000
@@ -55,7 +55,12 @@
/* Perform a sanity check on the argument type */
FFI_ASSERT(ffi_type_test((*ptr)));
+ /* Use the raw size for darwin and not the alignment rounded value.
+ We take care about this in prep_cif_machdep. */
+
+#ifndef POWERPC_DARWIN
arg->size = ALIGN(arg->size, (*ptr)->alignment);
+#endif
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
Index: src/powerpc/ffi_darwin.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffi_darwin.c,v
retrieving revision 1.7
diff -u -r1.7 ffi_darwin.c
--- src/powerpc/ffi_darwin.c 7 Feb 2003 04:31:20 -0000 1.7
+++ src/powerpc/ffi_darwin.c 4 Sep 2003 15:08:20 -0000
@@ -81,7 +81,6 @@
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
/*@=exportheader@*/
{
- const unsigned bytes = ecif->cif->bytes;
const unsigned flags = ecif->cif->flags;
/* 'stacktop' points at the previous backchain pointer. */
@@ -96,9 +95,10 @@
/* 'next_arg' grows up as we put parameters in it. */
unsigned *next_arg = stack + 6; // 6 reserved posistions.
- int i=ecif->cif->nargs;
+ int real_size;
+ int struct_align = 0;
+ int i = ecif->cif->nargs;
double double_tmp;
- float float_tmp;
void **p_argv = ecif->avalue;
unsigned gprvalue;
ffi_type** ptr = ecif->cif->arg_types;
@@ -113,7 +113,7 @@
// Return values are referenced by r3, so r4 is the first parameter.
if (flags & FLAG_RETVAL_REFERENCE)
*next_arg++ = (unsigned)(char *)ecif->rvalue;
-
+
/* Now for the arguments. */
for (;
i > 0;
@@ -164,15 +164,42 @@
goto putgpr;
case FFI_TYPE_STRUCT:
+ /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+ So we have to check for the ABI here. */
+ if (ecif->cif->abi == FFI_DARWIN) {
+ struct_align=(*ptr)->elements[0]->alignment;
+ real_size = (*ptr)->size;
+
+ if (struct_align < 4)
+ struct_align = 4;
+
+ char *dest_cpy = (char *) next_arg;
+
+ /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
+ SI 4 bytes) are aligned as if they were those modes.
+ Structures with 3 byte in size are padded upwards. */
+ if (real_size < 3)
+ dest_cpy += 4 - real_size;
+ memcpy((char*)dest_cpy, (char *)*p_argv,
+ (real_size + struct_align - 1) & ~(struct_align - 1));
+ next_arg+=((real_size + struct_align - 1) & ~(struct_align -1)) / 4;
+ break;
+ } else if (ecif->cif->abi == FFI_AIX) {
+ /* original implementation */
+ memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
+ next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);
+ break;
+ } else {
+ FFI_ASSERT(0);
+ break;
+ }
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
-#endif
-
memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);
- break;
-
+ break;
+#endif
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
@@ -187,7 +214,6 @@
}
/* Check that we didn't overrun the stack... */
- //FFI_ASSERT(copy_space >= (char *)next_arg);
//FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
//FFI_ASSERT((unsigned *)fpr_base
// <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
@@ -203,7 +229,7 @@
unsigned bytes;
int fparg_count = 0, intarg_count = 0;
unsigned flags = 0;
- unsigned struct_copy_size = 0;
+ int real_size = 0, struct_align = 0;
/* All the machine-independent calculation of cif->bytes will be wrong.
Redo the calculation for DARWIN. */
@@ -281,18 +307,37 @@
on the stack. If they go on the stack, they must
be 8-byte-aligned. */
if (intarg_count == NUM_GPR_ARG_REGISTERS-1
- || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
+ || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0))
intarg_count++;
intarg_count += 2;
break;
case FFI_TYPE_STRUCT:
+ /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+ So we have to check for the ABI here. */
+ if (cif->abi == FFI_DARWIN) {
+ struct_align = (*ptr)->elements[0]->alignment;
+ real_size = (*ptr)->size;
+
+ if (struct_align < 4)
+ struct_align = 4;
+
+ intarg_count+=((real_size + struct_align -1) & ~(struct_align -1))/4;
+ break;
+ } else if (cif->abi == FFI_AIX) {
+ /* original implementation */
+ intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
+ break;
+ } else {
+ FFI_ASSERT(0);
+ break;
+ }
+
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
-#endif
intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
break;
-
+#endif
default:
/* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */
@@ -303,9 +348,7 @@
if (fparg_count != 0)
flags |= FLAG_FP_ARGUMENTS;
- if (struct_copy_size != 0)
- flags |= FLAG_ARG_NEEDS_COPY;
-
+
/* Space for the FPR registers, if needed. */
if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
@@ -397,7 +440,7 @@
/* here I'd like to add the stack frame layout we use in darwin_closure.S
* and aix_clsoure.S
*
-/* SP previous -> +---------------------------------------+ <--- child frame
+ * SP previous -> +---------------------------------------+ <--- child frame
| back chain to caller 4 |
+---------------------------------------+ 4
| saved CR 4 |
@@ -464,22 +507,22 @@
FFI_ASSERT (cif->abi == FFI_DARWIN);
tramp = (unsigned int *) &closure->tramp[0];
- tramp[0] = 0x7c0802a6; /* mflr r0 */
- tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */
- tramp[4] = 0x7d6802a6; /* mflr r11 */
- tramp[5] = 0x818b0000; /* lwz r12,0(r11) /* function address */
- tramp[6] = 0x7c0803a6; /* mtlr r0 */
- tramp[7] = 0x7d8903a6; /* mtctr r12 */
- tramp[8] = 0x816b0004; /* lwz r11,4(r11) /* static chain */
- tramp[9] = 0x4e800420; /* bctr */
- *(void **) &tramp[2] = (void *)ffi_closure_ASM; /* function */
- *(void **) &tramp[3] = (void *)closure; /* context */
+ tramp[0] = 0x7c0802a6; /* mflr r0 */
+ tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */
+ tramp[4] = 0x7d6802a6; /* mflr r11 */
+ tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */
+ tramp[6] = 0x7c0803a6; /* mtlr r0 */
+ tramp[7] = 0x7d8903a6; /* mtctr r12 */
+ tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */
+ tramp[9] = 0x4e800420; /* bctr */
+ tramp[2] = (unsigned long) ffi_closure_ASM; /* function */
+ tramp[3] = (unsigned long) closure; /* context */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
- /* Flush the icache. Only necessary on Darwin */
+ /* Flush the icache. Only necessary on Darwin. */
flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
break;
@@ -558,6 +601,8 @@
long ng; /* number of general registers already used */
ffi_cif * cif;
double temp;
+ int struct_align = 0;
+ int real_size;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
@@ -569,9 +614,9 @@
returns the data directly to the caller. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
- rvalue = (void *)pgr;
- ng++;
+ rvalue = (void *) *pgr;
pgr++;
+ pst++;
}
i = 0;
@@ -612,7 +657,6 @@
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
- case FFI_TYPE_STRUCT:
/* there are 8 gpr registers used to pass values */
if (ng < 8) {
avalue[i] = pgr;
@@ -624,6 +668,63 @@
}
break;
+ case FFI_TYPE_STRUCT:
+ /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+ So we have to check for the ABI here. */
+ if (cif->abi == FFI_DARWIN) {
+ /* There are 8 gpr registers used to pass values. The rest
+ goes on to the stack pst.
+ The first element in a struct gives the alignment on darwin. */
+ struct_align = arg_types[i]->elements[0]->alignment;
+ real_size = arg_types[i]->size;
+
+ if (struct_align < 4)
+ struct_align = 4;
+
+ if (ng < 8) {
+ /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
+ SI 4 bytes) are aligned as if they were those modes.
+ Structures with 3 byte in size are padded upwards. */
+
+ if (real_size < 3) {
+ avalue[i] = (void*)pgr + 4 - real_size;
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = (void*)pgr;
+ ng+= ((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+ pgr+= ((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+ }
+ /* If the structure overlaps the register boundary, we have
+ to increase the stack address too. If we fill exactly 8
+ registers, then the next argument is on the beginning of the
+ stack. */
+ if ((ng != 8) && (ng + (((real_size + struct_align -1) &
+ ~(struct_align -1)) / 4) > 8))
+ pst+= 8 - ((real_size + struct_align -1) &
+ ~(struct_align -1)) / 4;
+ } else {
+ avalue[i] = (void*)pst;
+ pst+=((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+ }
+ break;
+ } else if (cif->abi == FFI_AIX) {
+ /* original implementation */
+ /* there are 8 gpr registers used to pass values */
+ if (ng < 8) {
+ avalue[i] = pgr;
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = pst;
+ pst++;
+ }
+ break;
+ } else {
+ FFI_ASSERT(0);
+ break;
+ }
+
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
/* long long ints are passed in two gpr's if available or in