aboutsummaryrefslogtreecommitdiff
path: root/libffi/src/powerpc
diff options
context:
space:
mode:
authorAndreas Tobler <a.tobler@schweiz.ch>2004-09-02 21:14:45 +0000
committerAndreas Tobler <a.tobler@schweiz.ch>2004-09-02 21:14:45 +0000
commitf6883007845bbb1526c486cc81cf3ced0fb2ea6e (patch)
treeeec92a0c95c7e91b95c4b2c40388a3ca9fc89d8b /libffi/src/powerpc
parentdce18685bdbd01a6c89386e0e04d14930c7042d3 (diff)
2004-09-02 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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@86992 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libffi/src/powerpc')
-rw-r--r--libffi/src/powerpc/darwin.S16
-rw-r--r--libffi/src/powerpc/darwin_closure.S10
-rw-r--r--libffi/src/powerpc/ffi_darwin.c97
3 files changed, 101 insertions, 22 deletions
diff --git a/libffi/src/powerpc/darwin.S b/libffi/src/powerpc/darwin.S
index cbbac960d4a..771238c5b7c 100644
--- a/libffi/src/powerpc/darwin.S
+++ b/libffi/src/powerpc/darwin.S
@@ -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 @@ L(done_return_value):
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 @@ LASFDE1:
.align 2
LEFDE1:
.data
- .align 2
+ .align 2
LLFB0$non_lazy_ptr:
- .long LFB0
+ .long LFB0
diff --git a/libffi/src/powerpc/darwin_closure.S b/libffi/src/powerpc/darwin_closure.S
index f608e6d0b9d..bf30c167fee 100644
--- a/libffi/src/powerpc/darwin_closure.S
+++ b/libffi/src/powerpc/darwin_closure.S
@@ -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 @@ LCFI0:
/* 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 @@ Lret_type3:
/* 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 @@ L_ffi_closure_helper_DARWIN$lazy_ptr:
.data
.align 2
LLFB1$non_lazy_ptr:
- .long LFB1
+ .long LFB1
diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c
index 6081b2f9085..d758f8f3af4 100644
--- a/libffi/src/powerpc/ffi_darwin.c
+++ b/libffi/src/powerpc/ffi_darwin.c
@@ -38,6 +38,7 @@ enum {
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 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
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 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
/* '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 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
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,26 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ 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;
+#endif
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
*(long long *)next_arg = *(long long *)*p_argv;
@@ -167,10 +189,6 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
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 +258,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
as the first argument. */
switch (cif->rtype->type)
{
+
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
+ flags |= FLAG_RETURNS_128BITS;
+ flags |= FLAG_RETURNS_FP;
+ break;
#endif
- /* Fall through. */
+
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
@@ -272,9 +294,8 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
/* 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 +310,19 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
intarg_count++;
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ 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;
+#endif
+
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
/* 'long long' arguments are passed as two words, but
@@ -302,9 +336,6 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
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 +440,8 @@ static void flush_range(char *, int);
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 +603,13 @@ int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
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 +619,7 @@ int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
ffi_cif * cif;
double temp;
unsigned size_al;
+ union ldu temp_ld;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
@@ -689,6 +728,34 @@ int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
pgr += 2;
break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ 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;
+#endif
default:
FFI_ASSERT(0);
}