This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

libffi powerpc64-linux long double


Corrects libffi long double function return value and arg handling for
power64-linux.  Darwin will probably want a similar change.

	* src/powerpc/ffi.c (ffi_prep_cif_machdep <FFI_LINUX64>): Correct
	long double function return and long double arg handling.
	(ffi_closure_helper_LINUX64): Formatting.  Delete unused "ng" var.
	Use "end_pfr" instead of "nf".  Correct long double handling.
	Localise "temp".
	* src/powerpc/linux64.S (ffi_call_LINUX64): Save f2 long double
	return value.
	* src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Allocate
	space for long double return value.  Adjust stack frame and offsets.
	Load f2 long double return.

Index: libffi/src/powerpc/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffi.c,v
retrieving revision 1.7
diff -u -p -r1.7 ffi.c
--- libffi/src/powerpc/ffi.c	11 Sep 2003 05:17:57 -0000	1.7
+++ libffi/src/powerpc/ffi.c	7 Feb 2004 12:11:37 -0000
@@ -446,6 +446,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
   int fparg_count = 0, intarg_count = 0;
   unsigned flags = 0;
   unsigned struct_copy_size = 0;
+  unsigned type = cif->rtype->type;
 
   if (cif->abi != FFI_LINUX64)
     {    
@@ -468,6 +469,11 @@ ffi_status ffi_prep_cif_machdep(ffi_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:
@@ -480,9 +486,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
        are allocated space and a pointer is passed as the first argument.
      For LINUX64:
      - integer values in gpr3;
-     - Structures/Unions and long double by reference;
-     - Single/double FP values in fpr1.  */
-  switch (cif->rtype->type)
+     - Structures/Unions by reference;
+     - Single/double FP values in fpr1, long double in fpr1,fpr2.  */
+  switch (type)
     {
     case FFI_TYPE_DOUBLE:
       flags |= FLAG_RETURNS_64BITS;
@@ -581,6 +587,12 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
       {
 	switch ((*ptr)->type)
 	  {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	  case FFI_TYPE_LONGDOUBLE:
+	    fparg_count += 2;
+	    intarg_count += 2;
+	    break;
+#endif
 	  case FFI_TYPE_FLOAT:
 	  case FFI_TYPE_DOUBLE:
 	    fparg_count++;
@@ -588,9 +600,6 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
 	    break;
 
 	  case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	  case FFI_TYPE_LONGDOUBLE:
-#endif
 	    intarg_count += ((*ptr)->size + 7) / 8;
 	    break;
 
@@ -863,7 +872,7 @@ ffi_closure_helper_SYSV (ffi_closure* cl
              pst++;
           }
 	  break;
-	
+
 	case FFI_TYPE_STRUCT:
 	  /* Structs are passed by reference. The address will appear in a 
 	     gpr if it is one of the first 8 arguments.  */
@@ -965,34 +974,28 @@ int hidden ffi_closure_helper_LINUX64 (f
 				       ffi_dblfl*);
 
 int hidden
-ffi_closure_helper_LINUX64 (ffi_closure* closure, void * rvalue, 
-            unsigned long * pst, ffi_dblfl * pfr)
+ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, 
+			    unsigned long *pst, ffi_dblfl *pfr)
 {
   /* rvalue is the pointer to space for return value in closure assembly */
   /* pst is the pointer to parameter save area
      (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
   /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
 
-  void **          avalue;
-  ffi_type **      arg_types;
-  long             i, avn;
-  long             nf;   /* number of floating registers already used */
-  long             ng;   /* number of general registers already used */
-  ffi_cif *        cif; 
-  double           temp; 
+  void **avalue;
+  ffi_type **arg_types;
+  long i, avn;
+  ffi_cif *cif; 
+  ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
 
   cif = closure->cif;
-  avalue = alloca(cif->nargs * sizeof(void *));
-
-  nf = 0;
-  ng = 0;
+  avalue = alloca (cif->nargs * sizeof (void *));
 
   /* Copy the caller's structure return value address so that the closure
      returns the data directly to the caller.  */
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     {
       rvalue = (void *) *pst;
-      ng++;
       pst++;
     }
 
@@ -1008,21 +1011,18 @@ ffi_closure_helper_LINUX64 (ffi_closure*
 	case FFI_TYPE_SINT8:
 	case FFI_TYPE_UINT8:
 	  avalue[i] = (char *) pst + 7;
-	  ng++;
 	  pst++;
 	  break;
            
 	case FFI_TYPE_SINT16:
 	case FFI_TYPE_UINT16:
 	  avalue[i] = (char *) pst + 6;
-	  ng++;
 	  pst++;
 	  break;
 
 	case FFI_TYPE_SINT32:
 	case FFI_TYPE_UINT32:
 	  avalue[i] = (char *) pst + 4;
-	  ng++;
 	  pst++;
 	  break;
 
@@ -1030,21 +1030,16 @@ ffi_closure_helper_LINUX64 (ffi_closure*
 	case FFI_TYPE_UINT64:
 	case FFI_TYPE_POINTER:
 	  avalue[i] = pst;
-	  ng++;
 	  pst++;
 	  break;
 
 	case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-	case FFI_TYPE_LONGDOUBLE:
-#endif
 	  /* Structures with size less than eight bytes are passed
 	     left-padded.  */
 	  if (arg_types[i]->size < 8)
 	    avalue[i] = (char *) pst + 8 - arg_types[i]->size;
 	  else
 	    avalue[i] = pst;
-	  ng += (arg_types[i]->size + 7) / 8;
 	  pst += (arg_types[i]->size + 7) / 8;
 	  break;
 
@@ -1056,16 +1051,15 @@ ffi_closure_helper_LINUX64 (ffi_closure*
 
           /* there are 13 64bit floating point registers */
 
-          if (nf < NUM_FPR_ARG_REGISTERS64) {
-             temp = pfr->d;
-             pfr->f = (float)temp;
-             avalue[i] = pfr;
-             pfr++;
-          } else {
-	     avalue[i] = pst;
-          }
-          nf++;
-	  ng++;
+          if (pfr < end_pfr)
+	    {
+	      double temp = pfr->d;
+	      pfr->f = (float) temp;
+	      avalue[i] = pfr;
+	      pfr++;
+	    }
+	  else
+	    avalue[i] = pst;
 	  pst++;
 	  break;
 
@@ -1073,17 +1067,38 @@ ffi_closure_helper_LINUX64 (ffi_closure*
 	  /* On the outgoing stack all values are aligned to 8 */
           /* there are 13 64bit floating point registers */
 
-          if (nf < NUM_FPR_ARG_REGISTERS64) {
-	     avalue[i] = pfr;
-             pfr++;
-          } else {
-	     avalue[i] = pst;
-          }
-          nf++;
-	  ng++;
+	  if (pfr < end_pfr)
+	    {
+	      avalue[i] = pfr;
+	      pfr++;
+	    }
+	  else
+	    avalue[i] = pst;
 	  pst++;
 	  break;
 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+	  if (prf + 1 < end_pfr)
+	    {
+	      avalue[i] = pfr;
+	      pfr += 2;
+	    }
+	  else
+	    {
+	      if (pfr < end_pfr)
+		{
+		  /* Passed partly in f13 and partly on the stack.
+		     Move it all to the stack.  */
+		  *pst = *(unsigned long *) pfr;
+		  pfr++;
+		}
+	      avalue[i] = pst;
+	    }
+	  pst += 2;
+	  break;
+#endif
+
 	default:
 	  FFI_ASSERT(0);
 	}
@@ -1096,5 +1111,4 @@ ffi_closure_helper_LINUX64 (ffi_closure*
 
   /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
   return cif->rtype->type;
-
 }
Index: libffi/src/powerpc/linux64.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/linux64.S,v
retrieving revision 1.5
diff -u -p -r1.5 linux64.S
--- libffi/src/powerpc/linux64.S	21 Oct 2003 19:01:56 -0000	1.5
+++ libffi/src/powerpc/linux64.S	7 Feb 2004 12:11:38 -0000
@@ -122,6 +122,7 @@ ffi_call_LINUX64:
 .Lfp_return_value:
 	bf	28, .Lfloat_return_value
 	stfd	%f1, 0(%r30)
+	stfd	%f2, 8(%r30)	/* It might be a long double */
 	b	.Ldone_return_value
 .Lfloat_return_value:
 	stfs	%f1, 0(%r30)
Index: libffi/src/powerpc/linux64_closure.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/linux64_closure.S,v
retrieving revision 1.5
diff -u -p -r1.5 linux64_closure.S
--- libffi/src/powerpc/linux64_closure.S	21 Oct 2003 19:01:56 -0000	1.5
+++ libffi/src/powerpc/linux64_closure.S	7 Feb 2004 12:11:38 -0000
@@ -30,24 +30,24 @@ ffi_closure_LINUX64:
 	std	%r0, 16(%r1)
 
 	# mandatory 48 bytes special reg save area + 64 bytes parm save area
-	# + 8 bytes retval area + 13*8 bytes fpr save area
-	stdu	%r1, -224(%r1)
+	# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
+	stdu	%r1, -240(%r1)
 .LCFI0:
 
 	# next save fpr 1 to fpr 13
-	stfd  %f1, 120+(0*8)(%r1)
-	stfd  %f2, 120+(1*8)(%r1)
-	stfd  %f3, 120+(2*8)(%r1)
-	stfd  %f4, 120+(3*8)(%r1)
-	stfd  %f5, 120+(4*8)(%r1)
-	stfd  %f6, 120+(5*8)(%r1)
-	stfd  %f7, 120+(6*8)(%r1)
-	stfd  %f8, 120+(7*8)(%r1)
-	stfd  %f9, 120+(8*8)(%r1)
-	stfd  %f10, 120+(9*8)(%r1)
-	stfd  %f11, 120+(10*8)(%r1)
-	stfd  %f12, 120+(11*8)(%r1)
-	stfd  %f13, 120+(12*8)(%r1)
+	stfd  %f1, 128+(0*8)(%r1)
+	stfd  %f2, 128+(1*8)(%r1)
+	stfd  %f3, 128+(2*8)(%r1)
+	stfd  %f4, 128+(3*8)(%r1)
+	stfd  %f5, 128+(4*8)(%r1)
+	stfd  %f6, 128+(5*8)(%r1)
+	stfd  %f7, 128+(6*8)(%r1)
+	stfd  %f8, 128+(7*8)(%r1)
+	stfd  %f9, 128+(8*8)(%r1)
+	stfd  %f10, 128+(9*8)(%r1)
+	stfd  %f11, 128+(10*8)(%r1)
+	stfd  %f12, 128+(11*8)(%r1)
+	stfd  %f13, 128+(12*8)(%r1)
 
 	# set up registers for the routine that actually does the work
 	# get the context pointer from the trampoline
@@ -58,10 +58,10 @@ ffi_closure_LINUX64:
 
 	# now load up the pointer to the parameter save area
 	# in the previous frame
-	addi %r5, %r1, 224 + 48
+	addi %r5, %r1, 240 + 48
 
 	# now load up the pointer to the saved fpr registers */
-	addi %r6, %r1, 120
+	addi %r6, %r1, 128
 
 	# make the call
 	bl .ffi_closure_helper_LINUX64
@@ -76,7 +76,7 @@ ffi_closure_LINUX64:
 	mflr %r4		# move address of .Lret to r4
 	sldi %r3, %r3, 4	# now multiply return type by 16
 	addi %r4, %r4, .Lret_type0 - .Lret
-	ld %r0, 224+16(%r1)
+	ld %r0, 240+16(%r1)
 	add %r3, %r3, %r4	# add contents of table to table address
 	mtctr %r3
 	bctr			# jump to it
@@ -89,33 +89,33 @@ ffi_closure_LINUX64:
 .Lret_type0:
 # case FFI_TYPE_VOID
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 	nop
 # case FFI_TYPE_INT
 	lwa %r3, 112+4(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_FLOAT
 	lfs %f1, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_DOUBLE
 	lfd %f1, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_LONGDOUBLE
 	lfd %f1, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
-	blr
+	lfd %f2, 112+8(%r1)
+	b .Lfinish
 # case FFI_TYPE_UINT8
 	lbz %r3, 112+7(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_SINT8
 	lbz %r3, 112+7(%r1)
@@ -126,42 +126,42 @@ ffi_closure_LINUX64:
 	lhz %r3, 112+6(%r1)
 	mtlr %r0
 .Lfinish:
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_SINT16
 	lha %r3, 112+6(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_UINT32
 	lwz %r3, 112+4(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_SINT32
 	lwa %r3, 112+4(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_UINT64
 	ld %r3, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_SINT64
 	ld %r3, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # case FFI_TYPE_STRUCT
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 	nop
 # case FFI_TYPE_POINTER
 	ld %r3, 112+0(%r1)
 	mtlr %r0
-	addi %r1, %r1, 224
+	addi %r1, %r1, 240
 	blr
 # esac
 .LFE1:
@@ -196,7 +196,7 @@ ffi_closure_LINUX64:
 	.byte	0x2	 # DW_CFA_advance_loc1
 	.byte	.LCFI0-.LFB1
 	.byte	0xe	 # DW_CFA_def_cfa_offset
-	.uleb128 224
+	.uleb128 240
 	.byte	0x11	 # DW_CFA_offset_extended_sf
 	.uleb128 0x41
 	.sleb128 -2

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]