This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] libffi darwin structure implementation (PPC)
- From: Andreas Tobler <toa at pop dot agri dot ch>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>, Geoff Keating <geoffk at geoffk dot org>,David Edelsohn <dje at watson dot ibm dot com>
- Cc: Anthony Green <green at redhat dot com>
- Date: Fri, 29 Aug 2003 20:59:06 +0200
- Subject: [patch] libffi darwin structure implementation (PPC)
Hi,
the attached patch implements the structure passing for ffi_call and
closures on PowerPC darwin. I hope I did it correct.
It passes all the testcases I recently posted for review. Tested also
with complete bootstrap on PowerPC darwin with no regressions.
Comments are welcome.
If no objections, I'd like to apply on main.
Thank you for review.
Andreas
2003-08-29 Andreas Tobler <a.tobler@schweiz.ch>
* src/prep_cif.c (initialize_aggregate): Don't align
ffi_arg for PowerPC Darwin.
* src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures
according to the ABI.
(ffi_prep_cif_machdep): Likewise.
(ffi_closure_helper_DARWIN): Likewise.
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 29 Aug 2003 18:45:12 -0000
@@ -55,7 +55,14 @@
/* Perform a sanity check on the argument type */
FFI_ASSERT(ffi_type_test((*ptr)));
+ /* Don't align arguments for darwin since the first element in a
+ * struct is responsible for alignment. 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 29 Aug 2003 18:45:12 -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;
@@ -168,11 +168,24 @@
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
+ struct_align=(*ptr)->elements[0]->alignment;
+ real_size = (*ptr)->size;
+
+ if (struct_align < 4)
+ struct_align = 4;
+
+ char *dest_cpy = (char *) next_arg;
- memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
- next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);
- break;
-
+ /* Structures with size less than 4 bytes are passed
+ * left-padded. Maybe we can pack 2 structs into one byte?
+ */
+ 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;
+
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
@@ -187,7 +200,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 +215,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,7 +293,7 @@
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;
@@ -290,9 +302,15 @@
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
- intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
- break;
+ 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;
+
default:
/* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */
@@ -303,9 +321,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 +413,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 +480,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] = 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 */
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 +574,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 +587,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 +630,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;
@@ -622,6 +639,45 @@
avalue[i] = pst;
pst++;
}
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* 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 with size less than four bytes are passed
+ * left-padded. We may put two in to one register
+ */
+ 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;
case FFI_TYPE_SINT64: