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]

[patch] libffi darwin structure implementation (PPC)


Hi,

the attached patch implements the structure passing for ffi_call and closures on PowerPC darwin. I hope I did it correct.

It passes all the testcases I recently posted for review. Tested also with complete bootstrap on PowerPC darwin with no regressions.

Comments are welcome.

If no objections, I'd like to apply on main.

Thank you for review.

Andreas

2003-08-29 Andreas Tobler <a.tobler@schweiz.ch>

	* src/prep_cif.c (initialize_aggregate): Don't align
	ffi_arg for PowerPC Darwin.
	* src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures
	according to the ABI.
	(ffi_prep_cif_machdep): Likewise.
	(ffi_closure_helper_DARWIN): Likewise.


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	29 Aug 2003 18:45:12 -0000
@@ -55,7 +55,14 @@
       /* Perform a sanity check on the argument type */
       FFI_ASSERT(ffi_type_test((*ptr)));
 
+      /* Don't align arguments for darwin since the first element in a 
+       * struct is responsible for alignment. 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	29 Aug 2003 18:45:12 -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;
@@ -168,11 +168,24 @@
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
         case FFI_TYPE_LONGDOUBLE:
 #endif
+	  struct_align=(*ptr)->elements[0]->alignment;
+	  real_size = (*ptr)->size;
+
+	  if (struct_align < 4) 
+	    struct_align = 4;
+
+	  char *dest_cpy = (char *) next_arg;
 	  
-	  memcpy((char*)next_arg, (char *)*p_argv, (*ptr)->size);
-	  next_arg+=(((((*ptr)->size) + 3) & ~0x3)/4);	
-        break;	  
-	  
+	  /* Structures with size less than 4 bytes are passed
+	   *  left-padded. Maybe we can pack 2 structs into one byte? 
+	   */	  
+	  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;
+
 	case FFI_TYPE_INT:
    	case FFI_TYPE_UINT32:
 	case FFI_TYPE_SINT32:
@@ -187,7 +200,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 +215,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,7 +293,7 @@
 	     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;
@@ -290,9 +302,15 @@
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 	case FFI_TYPE_LONGDOUBLE:
 #endif
-	  intarg_count+=(((*ptr)->size + 3) & ~0x3)/4;
-	  break;
+	  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;
+	  
 	default:
 	  /* Everything else is passed as a 4-byte word in a GPR, either
 	     the object itself or a pointer to it.  */
@@ -303,9 +321,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 +413,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 +480,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] = 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  */
 
       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 +574,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 +587,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 +630,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;
@@ -622,6 +639,45 @@
              avalue[i] = pst;
              pst++;
           }
+          break;
+
+	case FFI_TYPE_STRUCT:
+	  /* 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 with size less than four bytes are passed
+	     * left-padded. We may put two in to one register
+	     */
+	    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;
 
         case FFI_TYPE_SINT64:

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