From 2fe7404ad443eacbce92cc0a695bd31d9b263bbb Mon Sep 17 00:00:00 2001 From: Andreas Tobler Date: Thu, 2 Sep 2004 23:14:45 +0200 Subject: [PATCH] ffi_darwin.c: Add flag for longdouble return values. 2004-09-02 Andreas Tobler * 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. From-SVN: r86992 --- libffi/ChangeLog | 12 ++++ libffi/src/powerpc/darwin.S | 16 ++++- libffi/src/powerpc/darwin_closure.S | 10 +-- libffi/src/powerpc/ffi_darwin.c | 97 ++++++++++++++++++++++++----- libffi/src/types.c | 7 ++- 5 files changed, 119 insertions(+), 23 deletions(-) diff --git a/libffi/ChangeLog b/libffi/ChangeLog index e8456ee1a30..90e1f173ac8 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,15 @@ +2004-09-02 Andreas Tobler + + * 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. + 2004-09-02 Andreas Tobler * src/powerpc/aix.S: Remove whitespaces. 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); } diff --git a/libffi/src/types.c b/libffi/src/types.c index 2b31c26aeac..09863c076b5 100644 --- a/libffi/src/types.c +++ b/libffi/src/types.c @@ -80,11 +80,16 @@ FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); #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); -- 2.30.2