]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ffitarget.h (enum ffi_abi): Add FFI_LINUX.
authorAlan Modra <amodra@bigpond.net.au>
Thu, 23 Mar 2006 23:15:46 +0000 (23:15 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Thu, 23 Mar 2006 23:15:46 +0000 (09:45 +1030)
* src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX.  Default
for 32-bit using IBM extended double format.  Fix FFI_LAST_ABI.
* src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
FFI_TYPE_LONGDOUBLE.
(ffi_prep_args64): Assert using IBM extended double.
(ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
(ffi_call): Handle FFI_LINUX.
(ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
gpr3 return pointer as for struct return.  Handle FFI_LINUX
FFI_TYPE_LONGDOUBLE return and args.  Don't increment "nf"
unnecessarily.
* src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
for FFI_TYPE_LONGDOUBLE.  Move epilogue insns into case table.
Don't use r6 as pointer to results, instead use sp offset.  Don't
make a special call to load lr with case table address, instead
use offset from previous call.
* src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
* src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
return.

From-SVN: r112340

libffi/ChangeLog
libffi/src/powerpc/ffi.c
libffi/src/powerpc/ffitarget.h
libffi/src/powerpc/linux64.S
libffi/src/powerpc/ppc_closure.S
libffi/src/powerpc/sysv.S

index 0622223c04e1c5e86a55a564b85e4aa30ce7e14a..1d8b23899dd9e37079a17edb0510fd72e22355a9 100644 (file)
@@ -1,3 +1,26 @@
+2006-03-24  Alan Modra  <amodra@bigpond.net.au>
+
+       * src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX.  Default
+       for 32-bit using IBM extended double format.  Fix FFI_LAST_ABI.
+       * src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
+       FFI_TYPE_LONGDOUBLE.
+       (ffi_prep_args64): Assert using IBM extended double.
+       (ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
+       Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
+       (ffi_call): Handle FFI_LINUX.
+       (ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
+       gpr3 return pointer as for struct return.  Handle FFI_LINUX
+       FFI_TYPE_LONGDOUBLE return and args.  Don't increment "nf"
+       unnecessarily.
+       * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
+       for FFI_TYPE_LONGDOUBLE.  Move epilogue insns into case table.
+       Don't use r6 as pointer to results, instead use sp offset.  Don't
+       make a special call to load lr with case table address, instead
+       use offset from previous call.
+       * src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
+       * src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
+       return.
+
 2006-03-15  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments
index bfd7ab6768843b9c2475171564b3d4ddde43575e..39460d1b05a5362acf4caa26947672953de9309f 100644 (file)
@@ -197,6 +197,38 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       case FFI_TYPE_LONGDOUBLE:
+         if (ecif->cif->abi != FFI_LINUX)
+           goto do_struct;
+         double_tmp = (*p_argv.d)[0];
+
+         if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
+           {
+             if (intarg_count >= NUM_GPR_ARG_REGISTERS
+                 && intarg_count % 2 != 0)
+               {
+                 intarg_count++;
+                 next_arg.u++;
+               }
+             *next_arg.d = double_tmp;
+             next_arg.u += 2;
+             double_tmp = (*p_argv.d)[1];
+             *next_arg.d = double_tmp;
+             next_arg.u += 2;
+           }
+         else
+           {
+             *fpr_base.d++ = double_tmp;
+             double_tmp = (*p_argv.d)[1];
+             *fpr_base.d++ = double_tmp;
+           }
+
+         fparg_count += 2;
+         FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+         break;
+#endif
+
        case FFI_TYPE_UINT64:
        case FFI_TYPE_SINT64:
          if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
@@ -232,7 +264,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
 
        case FFI_TYPE_STRUCT:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-       case FFI_TYPE_LONGDOUBLE:
+       do_struct:
 #endif
          struct_copy_size = ((*ptr)->size + 15) & ~0xF;
          copy_space.c -= struct_copy_size;
@@ -433,6 +465,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
            *fpr_base.d++ = double_tmp;
          fparg_count++;
+         FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
          break;
 #endif
@@ -536,11 +569,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 
       /* Space for the mandatory parm save area and general registers.  */
       bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-      if (type == FFI_TYPE_LONGDOUBLE)
-       type = FFI_TYPE_DOUBLE;
-#endif
     }
 
   /* Return value handling.  The rules for SYSV are as follows:
@@ -549,14 +577,24 @@ ffi_prep_cif_machdep (ffi_cif *cif)
      - 64-bit integer values and structures between 5 and 8 bytes are returned
      in gpr3 and gpr4;
      - Single/double FP values are returned in fpr1;
-     - Larger structures and long double (if not equivalent to double) values
-     are allocated space and a pointer is passed as the first argument.
+     - Larger structures are allocated space and a pointer is passed as
+     the first argument.
+     - long doubles (if not equivalent to double) are returned in
+     fpr1,fpr2 for Linux and as for large structs for SysV.
      For LINUX64:
      - integer values in gpr3;
      - Structures/Unions by reference;
      - Single/double FP values in fpr1, long double in fpr1,fpr2.  */
   switch (type)
     {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+    case FFI_TYPE_LONGDOUBLE:
+      if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64)
+       goto byref;
+
+      flags |= FLAG_RETURNS_128BITS;
+      /* Fall through.  */
+#endif
     case FFI_TYPE_DOUBLE:
       flags |= FLAG_RETURNS_64BITS;
       /* Fall through.  */
@@ -598,15 +636,8 @@ ffi_prep_cif_machdep (ffi_cif *cif)
                }
            }
        }
-      /* else fall through.  */
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-    case FFI_TYPE_LONGDOUBLE:
-      if (type == FFI_TYPE_LONGDOUBLE && cif->abi == FFI_LINUX64)
-       {
-         flags |= FLAG_RETURNS_128BITS;
-         flags |= FLAG_RETURNS_FP;
-         break;
-       }
+    byref:
 #endif
       intarg_count++;
       flags |= FLAG_RETVAL_REFERENCE;
@@ -635,6 +666,13 @@ ffi_prep_cif_machdep (ffi_cif *cif)
            /* floating singles are not 8-aligned on stack */
            break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+         case FFI_TYPE_LONGDOUBLE:
+           if (cif->abi != FFI_LINUX)
+             goto do_struct;
+           fparg_count++;
+           /* Fall thru */
+#endif
          case FFI_TYPE_DOUBLE:
            fparg_count++;
            /* If this FP arg is going on the stack, it must be
@@ -664,7 +702,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 
          case FFI_TYPE_STRUCT:
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-         case FFI_TYPE_LONGDOUBLE:
+         do_struct:
 #endif
            /* We must allocate space for a copy of these to enforce
               pass-by-value.  Pad the space up to a multiple of 16
@@ -793,6 +831,7 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
 #ifndef POWERPC64
     case FFI_SYSV:
     case FFI_GCC_SYSV:
+    case FFI_LINUX:
       /*@-usedef@*/
       ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
       /*@=usedef@*/
@@ -920,14 +959,17 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
      For FFI_SYSV the result is passed in r3/r4 if the struct size is less
      or equal 8 bytes.  */
 
-  if (cif->rtype->type == FFI_TYPE_STRUCT)
+  if ((cif->rtype->type == FFI_TYPE_STRUCT
+       && !((cif->abi == FFI_SYSV) && (size <= 8)))
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+         && cif->abi != FFI_LINUX)
+#endif
+      )
     {
-      if (!((cif->abi == FFI_SYSV) && (size <= 8)))
-       {
-         rvalue = (void *) *pgr;
-         ng++;
-         pgr++;
-       }
+      rvalue = (void *) *pgr;
+      ng++;
+      pgr++;
     }
 
   i = 0;
@@ -989,6 +1031,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
          break;
 
        case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       do_struct:
+#endif
          /* Structs are passed by reference. The address will appear in a
             gpr if it is one of the first 8 arguments.  */
          if (ng < 8)
@@ -1060,7 +1105,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
               * naughty thing to do but...
               */
              avalue[i] = pst;
-             nf++;
              pst += 1;
            }
          break;
@@ -1080,11 +1124,32 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
              if (((long) pst) & 4)
                pst++;
              avalue[i] = pst;
-             nf++;
              pst += 2;
            }
          break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+       case FFI_TYPE_LONGDOUBLE:
+         if (cif->abi != FFI_LINUX)
+           goto do_struct;
+
+         if (nf < 7)
+           {
+             avalue[i] = pfr;
+             pfr += 2;
+             nf += 2;
+           }
+         else
+           {
+             if (((long) pst) & 4)
+               pst++;
+             avalue[i] = pst;
+             pst += 4;
+             nf = 8;
+           }
+         break;
+#endif
+
        default:
          FFI_ASSERT (0);
        }
@@ -1101,8 +1166,12 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
   if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
       && size <= 8)
     return FFI_SYSV_TYPE_SMALL_STRUCT + size;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+  else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+          && cif->abi != FFI_LINUX)
+    return FFI_TYPE_STRUCT;
+#endif
   return cif->rtype->type;
-
 }
 
 int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
index af63796c77c4c342194990e475f353c4f804bb8c..e7f62950371aa8454e976b0b08919e790b1f07f5 100644 (file)
@@ -43,10 +43,15 @@ typedef enum ffi_abi {
   FFI_SYSV,
   FFI_GCC_SYSV,
   FFI_LINUX64,
+  FFI_LINUX,
 # ifdef POWERPC64
   FFI_DEFAULT_ABI = FFI_LINUX64,
 # else
+#  if __LDBL_MANT_DIG__ == 106
+  FFI_DEFAULT_ABI = FFI_LINUX,
+#  else
   FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+#  endif
 # endif
 #endif
 
@@ -69,7 +74,7 @@ typedef enum ffi_abi {
   FFI_DEFAULT_ABI = FFI_SYSV,
 #endif
 
-  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+  FFI_LAST_ABI
 } ffi_abi;
 #endif
 
index 25b2c4f455be708aab5b857edaa1b969f40cf4d7..d72912da1edf8f492c6d0bab2834f2d07d8ae585 100644 (file)
@@ -120,12 +120,9 @@ ffi_call_LINUX64:
        blr
 
 .Lfp_return_value:
-       bt      27, .Lfd_return_value
        bf      28, .Lfloat_return_value
        stfd    %f1, 0(%r30)
-       b       .Ldone_return_value
-.Lfd_return_value:
-       stfd    %f1, 0(%r30)
+       bf      27, .Ldone_return_value
        stfd    %f2, 8(%r30)
        b       .Ldone_return_value
 .Lfloat_return_value:
index 370381378f91dafb77175dda2d26207c24160c12..356a0e326208b9edf80396a62d1d463f9cc4c7fd 100644 (file)
@@ -58,218 +58,178 @@ ENTRY(ffi_closure_SYSV)
 
        # make the call
        bl ffi_closure_helper_SYSV@local
-
+.Lret:
        # now r3 contains the return type
        # so use it to look up in a table
        # so we know how to deal with each type
 
        # look up the proper starting point in table
        # by using return type as offset
-       addi %r6,%r1,112   # get pointer to results area
-       bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
-       mflr %r4           # move to r4
-       slwi %r3,%r3,4     # now multiply return type by 16
-       add %r3,%r3,%r4    # add contents of table to table address
+
+       mflr %r4                # move address of .Lret to r4
+       slwi %r3,%r3,4          # now multiply return type by 16
+       addi %r4, %r4, .Lret_type0 - .Lret
+       lwz %r0,148(%r1)
+       add %r3,%r3,%r4         # add contents of table to table address
        mtctr %r3
-       bctr               # jump to it
+       bctr                    # jump to it
 .LFE1:
 
 # Each of the ret_typeX code fragments has to be exactly 16 bytes long
 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
 # first.
        .align 4
-
-       nop
-       nop
-       nop
-.Lget_ret_type0_addr:
-       blrl
-
 # case FFI_TYPE_VOID
 .Lret_type0:
-       b .Lfinish
-       nop
-       nop
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
        nop
 
 # case FFI_TYPE_INT
-.Lret_type1:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+.Lfinish:
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_FLOAT
-.Lret_type2:
-       lfs %f1,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lfs %f1,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_DOUBLE
-.Lret_type3:
-       lfd %f1,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lfd %f1,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_LONGDOUBLE
-.Lret_type4:
-       lfd %f1,0(%r6)
+       lfd %f1,112+0(%r1)
+       lfd %f2,112+8(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
-       nop
 
 # case FFI_TYPE_UINT8
-.Lret_type5:
-       lbz %r3,3(%r6)
-       b .Lfinish
-       nop
-       nop
+       lbz %r3,112+3(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT8
-.Lret_type6:
-       lbz %r3,3(%r6)
+       lbz %r3,112+3(%r1)
        extsb %r3,%r3
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_UINT16
-.Lret_type7:
-       lhz %r3,2(%r6)
-       b .Lfinish
-       nop
-       nop
+       lhz %r3,112+2(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT16
-.Lret_type8:
-       lha %r3,2(%r6)
-       b .Lfinish
-       nop
-       nop
+       lha %r3,112+2(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_UINT32
-.Lret_type9:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_SINT32
-.Lret_type10:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_TYPE_UINT64
-.Lret_type11:
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_SINT64
-.Lret_type12:
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_TYPE_STRUCT
-.Lret_type13:
-       b .Lfinish
-       nop
-       nop
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
        nop
 
 # case FFI_TYPE_POINTER
-.Lret_type14:
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # The return types below are only used when the ABI type is FFI_SYSV.
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
-.Lret_type15:
-# fall through.
-       lbz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lbz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
-.Lret_type16:
-# fall through.
-       lhz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lhz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
-.Lret_type17:
-# fall through.
-       lwz %r3,0(%r6)
+       lwz %r3,112+0(%r1)
        srwi %r3,%r3,8
+       mtlr %r0
        b .Lfinish
-       nop
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
-.Lret_type18:
-# this one handles the structs from above too.
-       lwz %r3,0(%r6)
-       b .Lfinish
-       nop
-       nop
+       lwz %r3,112+0(%r1)
+       mtlr %r0
+       addi %r1,%r1,144
+       blr
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
-.Lret_type19:
-# fall through.
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
        li %r5,24
        b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
-.Lret_type20:
-# fall through.
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
        li %r5,16
        b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
-.Lret_type21:
-# fall through.
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
        li %r5,8
        b .Lstruct567
 
 # case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
-.Lret_type22:
-# this one handles the above unhandled structs.
-       lwz %r3,0(%r6)
-       lwz %r4,4(%r6)
+       lwz %r3,112+0(%r1)
+       lwz %r4,112+4(%r1)
+       mtlr %r0
        b .Lfinish
-       nop
 
-# case done
-.Lfinish:
-
-       lwz %r0,148(%r1)
+.Lstruct567:
+       subfic %r6,%r5,32
+       srw %r4,%r4,%r5
+       slw %r6,%r3,%r6
+       srw %r3,%r3,%r5
+       or %r4,%r6,%r4
        mtlr %r0
        addi %r1,%r1,144
        blr
 
-.Lstruct567:
-       subfic %r0,%r5,32
-       srw %r4,%r4,%r5
-       slw %r0,%r3,%r0
-       srw %r3,%r3,%r5
-       or %r4,%r0,%r4
-       b .Lfinish
 END(ffi_closure_SYSV)
 
        .section        ".eh_frame",EH_FRAME_FLAGS,@progbits
index 6d5a707ec03cb7a392089f301ea4d56b0a3799c1..9a9a109d1ae9ad17fc3473071cbba350846fc1f2 100644 (file)
@@ -121,6 +121,8 @@ L(done_return_value):
 L(fp_return_value):
        bf      28,L(float_return_value)
        stfd    %f1,0(%r30)
+       bf      27,L(done_return_value)
+       stfd    %f2,8(%r30)
        b       L(done_return_value)
 L(float_return_value):
        stfs    %f1,0(%r30)