This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[patch] libffi longdouble for darwin
- From: Andreas Tobler <toa at pop dot agri dot ch>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, David Edelsohn <dje at watson dot ibm dot com>,Geoffrey Keating <geoffk at apple dot com>
- Cc: Java Patches <java-patches at gcc dot gnu dot org>
- Date: Wed, 01 Sep 2004 22:59:13 +0200
- Subject: [patch] libffi longdouble for darwin
Hi all,
the longer promised patch comes here. I hope to have it mostly right to
implement longdouble support on darwin (maybe even on AIX).
I'm still not finished with all the test cases but I'd like to see this
patch in 3.5 and so I have to hurry somehow. The test cases needs some
polishing. Testing was a bit difficult since the libc does not support
longdouble and so I had to tweak a bit.
I based my work on the ppc64 ABI (by Alanm, DJE et.al.) And on what's
currently implemented on darwin.
Tested on a G4.
David, if you say AIX behaves the same way as darwin regarding size and
alignment of longdoubles I adjust the file src/types.c. I could not test
so far on AIX.
Comments and corrections welcome.
Andreas
2004-09-01 Andreas Tobler <a.tobler@schweiz.ch>
* src/powerpc/ffi_darwin.c: Add flag for longdouble return values.
(ffi_prep_args): Handle longdouble arguments.
(ffi_prep_cif_machdep): Set flags for longdouble. Calculate space for
longdouble.
(ffi_closure_helper_DARWIN): Add closure handling for longdouble.
* src/powerpc/darwin.S (_ffi_call_DARWIN): Add handling of longdouble
values.
* src/powerpc/darwin_closure.S (_ffi_closure_ASM): Likewise.
* src/types.c: Defined longdouble size and alignment for darwin.
Index: src/types.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/types.c,v
retrieving revision 1.15
diff -u -r1.15 types.c
--- src/types.c 16 Mar 2004 19:17:33 -0000 1.15
+++ src/types.c 1 Sep 2004 20:43:04 -0000
@@ -80,11 +80,16 @@
#endif
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
-#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN
+#elif defined ARM || defined SH || defined POWERPC_AIX
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
+#elif defined POWERPC_DARWIN
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+
#elif defined SPARC
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
Index: src/powerpc/darwin.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/darwin.S,v
retrieving revision 1.9
diff -u -r1.9 darwin.S
--- src/powerpc/darwin.S 27 Apr 2004 01:45:19 -0000 1.9
+++ src/powerpc/darwin.S 1 Sep 2004 20:43:04 -0000
@@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
darwin.S - Copyright (c) 2000 John Hornkvist
+ Copyright (c) 2004 Free Software Foundation, Inc.
PowerPC Assembly glue.
@@ -142,12 +143,23 @@
blr
L(fp_return_value):
+ /* Do we have long double to store? */
+ bf 31,L(fd_return_value)
+ stfd f1,0(r30)
+ stfd f2,8(r30)
+ b L(done_return_value)
+
+L(fd_return_value):
+ /* Do we have double to store? */
bf 28,L(float_return_value)
stfd f1,0(r30)
b L(done_return_value)
+
L(float_return_value):
+ /* We only have a float to store. */
stfs f1,0(r30)
b L(done_return_value)
+
LFE1:
/* END(_ffi_call_DARWIN) */
@@ -218,6 +230,6 @@
.align 2
LEFDE1:
.data
- .align 2
+ .align 2
LLFB0$non_lazy_ptr:
- .long LFB0
+ .long LFB0
Index: src/powerpc/darwin_closure.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/darwin_closure.S,v
retrieving revision 1.8
diff -u -r1.8 darwin_closure.S
--- src/powerpc/darwin_closure.S 27 Apr 2004 01:45:19 -0000 1.8
+++ src/powerpc/darwin_closure.S 1 Sep 2004 20:43:04 -0000
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
- darwin_closure.S - Copyright (c) 2002 2003 Free Software Foundation,
+ darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation,
Inc. based on ppc_closure.S
PowerPC Assembly glue.
@@ -42,8 +42,8 @@
/* 24 Bytes (Linkage Area)
32 Bytes (outgoing parameter area, always reserved)
104 Bytes (13*8 from FPR)
- 8 Bytes (result)
- 168 Bytes */
+ 16 Bytes (result)
+ 176 Bytes */
stwu r1,-176(r1) /* skip over caller save area
keep stack aligned to 16. */
@@ -150,9 +150,9 @@
/* case FFI_TYPE_LONGDOUBLE */
Lret_type4:
lfd f1,0(r5)
+ lfd f2,8(r5)
b Lfinish
nop
- nop
/* case FFI_TYPE_UINT8 */
Lret_type5:
@@ -301,4 +301,4 @@
.data
.align 2
LLFB1$non_lazy_ptr:
- .long LFB1
+ .long LFB1
Index: src/powerpc/ffi_darwin.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffi_darwin.c,v
retrieving revision 1.12
diff -u -r1.12 ffi_darwin.c
--- src/powerpc/ffi_darwin.c 30 Jun 2004 09:55:13 -0000 1.12
+++ src/powerpc/ffi_darwin.c 1 Sep 2004 20:43:05 -0000
@@ -38,6 +38,7 @@
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
FLAG_RETURNS_FP = 1 << (31-29),
FLAG_RETURNS_64BITS = 1 << (31-28),
+ FLAG_RETURNS_128BITS = 1 << (31-31),
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
@@ -86,7 +87,7 @@
const unsigned flags = ecif->cif->flags;
/* 'stacktop' points at the previous backchain pointer. */
- unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned));
+ unsigned *const stacktop = stack + (bytes / sizeof(unsigned));
/* 'fpr_base' points at the space for fpr1, and grows upwards as
we use FPR registers. */
@@ -95,7 +96,7 @@
/* 'next_arg' grows up as we put parameters in it. */
- unsigned *next_arg = stack + 6; /* 6 reserved posistions. */
+ unsigned *next_arg = stack + 6; /* 6 reserved positions. */
int i = ecif->cif->nargs;
double double_tmp;
@@ -137,6 +138,7 @@
fparg_count++;
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
+
case FFI_TYPE_DOUBLE:
double_tmp = *(double *)*p_argv;
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
@@ -148,6 +150,24 @@
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
+ case FFI_TYPE_LONGDOUBLE:
+ double_tmp = ((double *)*p_argv)[0];
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ *(double *)next_arg = double_tmp;
+ else
+ *fpr_base++ = double_tmp;
+ next_arg += 2;
+ fparg_count++;
+ double_tmp = ((double *)*p_argv)[1];
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ *(double *)next_arg = double_tmp;
+ else
+ *fpr_base++ = double_tmp;
+ next_arg += 2;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
*(long long *)next_arg = *(long long *)*p_argv;
@@ -167,10 +187,6 @@
goto putgpr;
case FFI_TYPE_STRUCT:
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
dest_cpy = (char *) next_arg;
/* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
@@ -240,10 +256,11 @@
as the first argument. */
switch (cif->rtype->type)
{
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
-#endif
- /* Fall through. */
+ flags |= FLAG_RETURNS_128BITS;
+ flags |= FLAG_RETURNS_FP;
+ break;
+
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
@@ -272,9 +289,8 @@
/* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
- goes on the stack. Structures and long doubles (if not equivalent
- to double) are passed as a pointer to a copy of the structure.
- Stuff on the stack needs to keep proper alignment. */
+ goes on the stack. Structures are passed as a pointer to a copy of
+ the structure. Stuff on the stack needs to keep proper alignment. */
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
switch ((*ptr)->type)
@@ -289,6 +305,16 @@
intarg_count++;
break;
+ case FFI_TYPE_LONGDOUBLE:
+ fparg_count += 2;
+ /* If this FP arg is going on the stack, it must be
+ 8-byte-aligned. */
+ if (fparg_count > NUM_FPR_ARG_REGISTERS
+ && intarg_count%2 != 0)
+ intarg_count++;
+ intarg_count +=2;
+ break;
+
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
/* 'long long' arguments are passed as two words, but
@@ -302,9 +328,6 @@
break;
case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
size_al = (*ptr)->size;
/* If the first member of the struct is a double, then align
the struct to double-word.
@@ -409,8 +432,8 @@
points to one of these. */
typedef struct aix_fd_struct {
- void *code_pointer;
- void *toc;
+ void *code_pointer;
+ void *toc;
} aix_fd;
/* here I'd like to add the stack frame layout we use in darwin_closure.S
@@ -572,6 +595,13 @@
pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM
pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */
+ typedef double ldbits[2];
+
+ union ldu
+ {
+ ldbits lb;
+ long double ld;
+ };
void ** avalue;
ffi_type ** arg_types;
@@ -581,6 +611,7 @@
ffi_cif * cif;
double temp;
unsigned size_al;
+ union ldu temp_ld;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
@@ -689,6 +720,32 @@
pgr += 2;
break;
+ case FFI_TYPE_LONGDOUBLE:
+ /* A long double value consumes four GPRs and two FPRs.
+ There are 13 64bit floating point registers. */
+ if (nf < NUM_FPR_ARG_REGISTERS - 1)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ }
+ /* Here we have the situation where one part of the long double
+ is stored in fpr13 and the other part is already on the stack.
+ We use a union to pass the long double to avalue[i]. */
+ else if (nf == NUM_FPR_ARG_REGISTERS - 1)
+ {
+ memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits));
+ memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits));
+ avalue[i] = &temp_ld.ld;
+ }
+ else
+ {
+ avalue[i] = pgr;
+ }
+ nf += 2;
+ ng += 4;
+ pgr += 4;
+ break;
+
default:
FFI_ASSERT(0);
}