ffi_darwin.c: Add flag for longdouble return values.
authorAndreas Tobler <a.tobler@schweiz.ch>
Thu, 2 Sep 2004 21:14:45 +0000 (23:14 +0200)
committerAndreas Tobler <andreast@gcc.gnu.org>
Thu, 2 Sep 2004 21:14:45 +0000 (23:14 +0200)
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.

From-SVN: r86992

libffi/ChangeLog
libffi/src/powerpc/darwin.S
libffi/src/powerpc/darwin_closure.S
libffi/src/powerpc/ffi_darwin.c
libffi/src/types.c

index e8456ee1a30cf2f9fe599eedad0fcad2daae544c..90e1f173ac846630551f4c43b0728a7426d312b0 100644 (file)
@@ -1,3 +1,15 @@
+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.
+
 2004-09-02  Andreas Tobler  <a.tobler@schweiz.ch>
 
        * src/powerpc/aix.S: Remove whitespaces.
index cbbac960d4a6c382673377aa2de486f9c4cea8d7..771238c5b7c57098e23cb787b13cbcd9c3d45e80 100644 (file)
@@ -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
index f608e6d0b9d447534b8b9f6c9644e9ca77942e0f..bf30c167feec94d3bb19ef85b89ee51bc0a96dd0 100644 (file)
@@ -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
index 6081b2f908553a7e73225e37f33d6f95ee1bbc76..d758f8f3af4a613ea0c07c7385cb0b665cce7042 100644 (file)
@@ -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);
        }
index 2b31c26aeac41374bf2454926ac2c9d554167522..09863c076b508bd664dbf5c2d33cbd567fd4042f 100644 (file)
@@ -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);