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]

Re: [patch] libffi darwin structure implementation (PPC)


Hi all,

Here a reworked diff.

I took the suggestions from Andrew and the ones from David.
I hope it is better now.

Tested with the just commited framework :)


What does apple say ?



Thanks for review.


Andreas

2003-09-04 Andreas Tobler <a.tobler@schweiz.ch>

	* src/prep_cif.c (initialize_aggregate): Don't use rounded size
	of ffi_arg for PowerPC Darwin.
	* src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures
	according to the OS-X ABI. Split AIX FFI_STRUCT case.
	(ffi_prep_cif_machdep): Likewise.
	(ffi_closure_helper_DARWIN): Likewise.
	(ffi_prep_clousure): Change the branch statement. Avoid the
	casts on lvalues.
Index: src/prep_cif.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/prep_cif.c,v
retrieving revision 1.5
diff -u -r1.5 prep_cif.c
--- src/prep_cif.c	30 Sep 2002 11:59:42 -0000	1.5
+++ src/prep_cif.c	4 Sep 2003 15:08:20 -0000
@@ -55,7 +55,12 @@
       /* Perform a sanity check on the argument type */
       FFI_ASSERT(ffi_type_test((*ptr)));
 
+      /* Use the raw size for darwin and not the alignment rounded value.
+	 We take care about this in prep_cif_machdep.  */
+
+#ifndef POWERPC_DARWIN
       arg->size = ALIGN(arg->size, (*ptr)->alignment);
+#endif
       arg->size += (*ptr)->size;
 
       arg->alignment = (arg->alignment > (*ptr)->alignment) ? 
Index: src/powerpc/ffi_darwin.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/powerpc/ffi_darwin.c,v
retrieving revision 1.7
diff -u -r1.7 ffi_darwin.c
--- src/powerpc/ffi_darwin.c	7 Feb 2003 04:31:20 -0000	1.7
+++ src/powerpc/ffi_darwin.c	4 Sep 2003 15:08:20 -0000
@@ -81,7 +81,6 @@
 void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
 /*@=exportheader@*/
 {
-  const unsigned bytes = ecif->cif->bytes;
   const unsigned flags = ecif->cif->flags; 
 
   /* 'stacktop' points at the previous backchain pointer.  */
@@ -96,9 +95,10 @@
   /* 'next_arg' grows up as we put parameters in it.  */
   unsigned *next_arg = stack + 6; // 6 reserved posistions. 
 
-  int i=ecif->cif->nargs;
+  int real_size;
+  int struct_align = 0;
+  int i = ecif->cif->nargs;
   double double_tmp;
-  float float_tmp;
   void **p_argv = ecif->avalue;
   unsigned gprvalue;
   ffi_type** ptr = ecif->cif->arg_types;
@@ -113,7 +113,7 @@
   // Return values are referenced by r3, so r4 is the first parameter.
   if (flags & FLAG_RETVAL_REFERENCE)
     *next_arg++ = (unsigned)(char *)ecif->rvalue;
-
+  
   /* Now for the arguments.  */
   for (;
        i > 0;
@@ -164,15 +164,42 @@
 	  goto putgpr;
 
         case FFI_TYPE_STRUCT:
+	  /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+	     So we have to check for the ABI here.  */
+	  if (ecif->cif->abi == FFI_DARWIN) {
+	    struct_align=(*ptr)->elements[0]->alignment;
+	    real_size = (*ptr)->size;
+	    
+	    if (struct_align < 4) 
+	      struct_align = 4;
+	    
+	    char *dest_cpy = (char *) next_arg;
+	    
+	    /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, 
+	       SI 4 bytes) are aligned as if they were those modes. 
+	       Structures with 3 byte in size are padded upwards.  */
+	    if (real_size < 3)
+	      dest_cpy += 4 - real_size;
+	    memcpy((char*)dest_cpy, (char *)*p_argv,
+		   (real_size + struct_align - 1) & ~(struct_align - 1));
+	    next_arg+=((real_size + struct_align - 1) & ~(struct_align -1)) / 4;
+	    break;
+	  } else if (ecif->cif->abi == FFI_AIX) {
+	    /* original implementation */
+	    memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
+	    next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);
+	    break;
+	  } else {
+	    FFI_ASSERT(0);
+	    break;
+	  }
 
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
         case FFI_TYPE_LONGDOUBLE:
-#endif
-	  
 	  memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
 	  next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);	
-        break;	  
-	  
+	  break;
+#endif
 	case FFI_TYPE_INT:
    	case FFI_TYPE_UINT32:
 	case FFI_TYPE_SINT32:
@@ -187,7 +214,6 @@
     }
 
   /* Check that we didn't overrun the stack...  */
-  //FFI_ASSERT(copy_space >= (char *)next_arg);
   //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
   //FFI_ASSERT((unsigned *)fpr_base
   //	     <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
@@ -203,7 +229,7 @@
   unsigned bytes;
   int fparg_count = 0, intarg_count = 0;
   unsigned flags = 0;
-  unsigned struct_copy_size = 0;
+  int real_size = 0, struct_align = 0;
 
   /* All the machine-independent calculation of cif->bytes will be wrong.
      Redo the calculation for DARWIN.  */
@@ -281,18 +307,37 @@
 	     on the stack.  If they go on the stack, they must
 	     be 8-byte-aligned.  */
 	  if (intarg_count == NUM_GPR_ARG_REGISTERS-1
-	      || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
+	      || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0))
 	    intarg_count++;
 	  intarg_count += 2;
 	  break;
 
 	case FFI_TYPE_STRUCT:
+	  /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+	     So we have to check for the ABI here.  */
+	  if (cif->abi == FFI_DARWIN) {
+	    struct_align = (*ptr)->elements[0]->alignment;
+	    real_size = (*ptr)->size;
+	    
+	    if (struct_align < 4)
+	      struct_align = 4;
+	    
+	    intarg_count+=((real_size + struct_align -1) & ~(struct_align -1))/4;
+	    break;
+	  } else if (cif->abi == FFI_AIX) {
+	    /* original implementation */
+	    intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
+	    break;
+	  } else {
+	    FFI_ASSERT(0);
+	    break;
+	  }
+	  
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 	case FFI_TYPE_LONGDOUBLE:
-#endif
 	  intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
 	  break;
-
+#endif	  
 	default:
 	  /* Everything else is passed as a 4-byte word in a GPR, either
 	     the object itself or a pointer to it.  */
@@ -303,9 +348,7 @@
 
   if (fparg_count != 0)
     flags |= FLAG_FP_ARGUMENTS;
-  if (struct_copy_size != 0)
-    flags |= FLAG_ARG_NEEDS_COPY;
-  
+
   /* Space for the FPR registers, if needed.  */
   if (fparg_count != 0)
     bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
@@ -397,7 +440,7 @@
 /* here I'd like to add the stack frame layout we use in darwin_closure.S
  * and aix_clsoure.S
  *
-/* SP previous -> +---------------------------------------+ <--- child frame
+ * SP previous -> +---------------------------------------+ <--- child frame
                   | back chain to caller 4                | 
                   +---------------------------------------+ 4
                   | saved CR 4                            | 
@@ -464,22 +507,22 @@
       FFI_ASSERT (cif->abi == FFI_DARWIN);
 
       tramp = (unsigned int *) &closure->tramp[0];
-      tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
-      tramp[1] = 0x4800000d;  /*   bl      10 <trampoline_initial+0x10> */
-      tramp[4] = 0x7d6802a6;  /*   mflr    r11 */
-      tramp[5] = 0x818b0000;  /*   lwz     r12,0(r11)  /* function address */
-      tramp[6] = 0x7c0803a6;  /*   mtlr    r0  */
-      tramp[7] = 0x7d8903a6;  /*   mtctr   r12 */
-      tramp[8] = 0x816b0004;  /*   lwz     r11,4(r11)  /* static chain */
-      tramp[9] = 0x4e800420;  /*   bctr */
-      *(void **) &tramp[2] = (void *)ffi_closure_ASM; /* function */
-      *(void **) &tramp[3] = (void *)closure;          /* context */
+      tramp[0] = 0x7c0802a6;  /*   mflr    r0  */
+      tramp[1] = 0x429f000d;  /*   bcl-    20,4*cr7+so,0x10  */
+      tramp[4] = 0x7d6802a6;  /*   mflr    r11  */
+      tramp[5] = 0x818b0000;  /*   lwz     r12,0(r11) function address  */
+      tramp[6] = 0x7c0803a6;  /*   mtlr    r0   */
+      tramp[7] = 0x7d8903a6;  /*   mtctr   r12  */
+      tramp[8] = 0x816b0004;  /*   lwz     r11,4(r11) static chain  */
+      tramp[9] = 0x4e800420;  /*   bctr  */
+      tramp[2] = (unsigned long) ffi_closure_ASM; /* function  */
+      tramp[3] = (unsigned long) closure; /* context  */
 
       closure->cif = cif;
       closure->fun = fun;
       closure->user_data = user_data;
 
-      /* Flush the icache. Only necessary on Darwin  */
+      /* Flush the icache. Only necessary on Darwin.  */
       flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
      
       break;
@@ -558,6 +601,8 @@
   long             ng;   /* number of general registers already used */
   ffi_cif *        cif;
   double           temp;
+  int              struct_align = 0;
+  int              real_size;
 
   cif = closure->cif;
   avalue = alloca(cif->nargs * sizeof(void *));
@@ -569,9 +614,9 @@
      returns the data directly to the caller.  */
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     {
-      rvalue = (void *)pgr;
-      ng++;      
+      rvalue = (void *) *pgr;
       pgr++;
+      pst++;
     }
 
   i = 0;
@@ -612,7 +657,6 @@
         case FFI_TYPE_SINT32:
         case FFI_TYPE_UINT32:
         case FFI_TYPE_POINTER:
-        case FFI_TYPE_STRUCT:
         /* there are 8 gpr registers used to pass values */
           if (ng < 8) {  
              avalue[i] = pgr;
@@ -624,6 +668,63 @@
           }
           break;
 
+	case FFI_TYPE_STRUCT:
+	  /* In case of structs the Darwin OS-X ABI != AIX ABI anymore.
+	     So we have to check for the ABI here.  */
+	  if (cif->abi == FFI_DARWIN) {
+	    /* There are 8 gpr registers used to pass values. The rest
+	       goes on to the stack pst.
+	       The first element in a struct gives the alignment on darwin.  */
+	    struct_align = arg_types[i]->elements[0]->alignment;
+	    real_size = arg_types[i]->size;
+	    
+	    if (struct_align < 4) 
+	      struct_align = 4;
+	    
+	    if (ng < 8) {  
+	      /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, 
+		 SI 4 bytes) are aligned as if they were those modes. 
+		 Structures with 3 byte in size are padded upwards.  */
+
+	      if (real_size < 3) {
+		avalue[i] = (void*)pgr + 4 - real_size;
+		ng++;
+		pgr++;
+	      } else {
+		avalue[i] = (void*)pgr;
+		ng+= ((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+		pgr+= ((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+	      }
+	      /* If the structure overlaps the register boundary, we have 
+		 to increase the stack address too. If we fill exactly 8 
+		 registers, then the next argument is on the beginning of the 
+		 stack.  */
+	      if ((ng != 8) && (ng + (((real_size + struct_align -1) & 
+				       ~(struct_align -1)) / 4) > 8))
+		pst+= 8 - ((real_size + struct_align -1) & 
+			   ~(struct_align -1)) / 4;
+	    } else {
+	      avalue[i] = (void*)pst;
+	      pst+=((real_size + struct_align -1) & ~(struct_align -1)) / 4;
+	    }
+	    break;
+	  } else if (cif->abi == FFI_AIX) {
+	    /* original implementation */
+	    /* there are 8 gpr registers used to pass values */
+	    if (ng < 8) {  
+	      avalue[i] = pgr;
+	      ng++;
+	      pgr++;
+	    } else {
+	      avalue[i] = pst;
+	      pst++;
+	    }
+	    break;
+	  } else {
+	    FFI_ASSERT(0);
+	    break;
+	  }
+	  
         case FFI_TYPE_SINT64:
         case FFI_TYPE_UINT64:
           /* long long ints are passed in two gpr's if available or in 

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