PATCH: Fix 2 PPC/SYSV varargs problems

Franz Sirl Franz.Sirl-kernel at lauterbach.com
Fri Apr 30 10:09:09 EST 1999


Hi,

this patch is supposed to fix the following problems on PPC/SYSV:

1. the varargs save area calculation bug, this is a hack and Richard ;-) 
probably won't like it, but maybe it's good enough for egcs-1.2

2. if you call a function that uses more then 8 float args before all 
integer argument passing registers are consumed, egcs will missetup the 
calling sequence. I introduced a new variable cum->sysv_fwords in the 
CUMULATIVE_ARGS struct, which counts the saved float words and adjusted 
cum->words where needed (I hope). There maybe better/nicer ways to 
implement that, so tell me if you want a different solution. A testcase is 
attached, the original problem happens with gnuplot.

Franz.


-------------- next part --------------
#include <stdarg.h>

inline void debug(const char *fp,const char *msg,...)
{
       va_list ap;
       double df;
   

       if (*fp != '1')
             abort();
       if (*msg != '2')
             abort();
   
       va_start( ap, msg );
   
       df = va_arg(ap,double);
       if (df <1.09 || df >1.11)
             abort();
       df = va_arg(ap,double);
       if (df <1.19 || df >1.21)
             abort();
       df = va_arg(ap,double);
       if (df <1.29 || df >1.31)
             abort();
       df = va_arg(ap,double);
       if (df <1.39 || df >1.41)
             abort();
       df = va_arg(ap,double);
       if (df <1.49 || df >1.51)
             abort();
       if ( *va_arg(ap,char*) != '3')
             abort();
       if ( *va_arg(ap,char*) != '4')
             abort();
       if ( *va_arg(ap,char*) != '5')
             abort();
       df = va_arg(ap,double);
       if (df <1.59 || df >1.61)
             abort();
       df = va_arg(ap,double);
       if (df <1.69 || df >1.71)
             abort();
       df = va_arg(ap,double);
       if (df <1.79 || df >1.81)
             abort();
       df = va_arg(ap,double);
       if (df <1.89 || df >1.91)
             abort();
       if ( va_arg(ap,int) != 101)
             abort();
       if ( va_arg(ap,int) != 102)
             abort();
       if ( va_arg(ap,int) != 103)
             abort();
       if ( va_arg(ap,int) != 104)
             abort();
       if ( *va_arg(ap,char*) != '6')
             abort();
       if ( va_arg(ap,int) != 105)
             abort();
       if ( va_arg(ap,int) != 106)
             abort();
       if ( va_arg(ap,int) != 107)
             abort();
       if ( va_arg(ap,int) != 108)
             abort();
       if ( va_arg(ap,int) != 109)
             abort();

   
       if ( va_arg(ap,int) != 110)
             abort();

       va_end( ap );
}

int main(void)
{
     debug("1 filepointer", "2 format", 1.1,1.2,1.3,1.4,1.5, "3","4","5", 1.6,1.7,1.8,1.9, 101,102,103,104, "6", 105,106,107,108,109,110);
     exit(0);
}

-------------- next part --------------
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.141
diff -u -p -r1.141 expr.c
--- expr.c	1999/04/27 05:34:43	1.141
+++ gcc/expr.c	1999/04/28 22:23:47
@@ -8951,7 +8951,13 @@ expand_builtin (exp, target, subtarget, 
 		if (wordnum < 0 || wordnum >= nwords || TREE_INT_CST_HIGH (arg))
 		  error ("argument of `__builtin_args_info' out of range");
 		else
-		  return GEN_INT (word_ptr[wordnum]);
+		  {
+#ifdef CUMULATIVE_ARG_INFO_IS_RTX
+		    if (CUMULATIVE_ARG_INFO_IS_RTX(wordnum))
+		      return word_ptr[wordnum];
+#endif
+		    return GEN_INT (word_ptr[wordnum]);
+	          }
 	      }
 	  }
 	else
Index: va-ppc.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/ginclude/va-ppc.h,v
retrieving revision 1.4
diff -u -p -r1.4 va-ppc.h
--- va-ppc.h	1998/12/16 21:19:40	1.4
+++ gcc/ginclude/va-ppc.h	1999/04/28 23:23:10
@@ -80,8 +80,7 @@ __extension__ ({							\
 									\
    (AP)->gpr = (__words < 8) ? __words : 8;				\
    (AP)->fpr = __va_fregno - 33;					\
-   (AP)->reg_save_area = (((char *) __builtin_frame_address (0))	\
-			  + __va_varargs_offset);			\
+   (AP)->reg_save_area = ((char *) __builtin_args_info (8));		\
    __va_overflow(AP) = ((char *)__builtin_saveregs ()			\
 			+ (((__words >= 8) ? __words - 8 : 0)		\
 			   * sizeof (long)));				\
Index: rs6000.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.45
diff -u -p -r1.45 rs6000.h
--- rs6000.h	1999/04/27 12:39:56	1.45
+++ gcc/config/rs6000/rs6000.h	1999/04/29 23:16:17
@@ -1445,15 +1445,19 @@ extern int rs6000_sysv_varargs_p;
 
 typedef struct rs6000_args
 {
-  int words;			/* # words uses for passing GP registers */
+  int words;			/* # words uses for passing GP+FP registers */
   int fregno;			/* next available FP register */
   int nargs_prototype;		/* # args left in the current prototype */
   int orig_nargs;		/* Original value of nargs_prototype */
   int varargs_offset;		/* offset of the varargs save area */
   int prototype;		/* Whether a prototype was defined */
   int call_cookie;		/* Do special things for this call */
+  int sysv_fwords;		/* # words uses for passing FP registers */
+  void *save_area;		/* setup with rtx pointing to varargs_save_area */
 } CUMULATIVE_ARGS;
 
+#define CUMULATIVE_ARG_INFO_IS_RTX(idx) ((idx) == 8)
+
 /* Define intermediate macro to compute the size (in registers) of an argument
    for the RS/6000.  */
 
Index: rs6000.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.66
diff -u -p -r1.66 rs6000.c
--- rs6000.c	1999/04/27 12:39:58	1.66
+++ gcc/config/rs6000/rs6000.c	1999/04/29 23:16:29
@@ -1256,6 +1261,7 @@ init_cumulative_args (cum, fntype, libna
   cum->fregno = FP_ARG_MIN_REG;
   cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
   cum->call_cookie = CALL_NORMAL;
+  cum->sysv_fwords = 0;
 
   if (incoming)
     {
@@ -1381,10 +1387,10 @@ function_arg_advance (cum, mode, type, n
       /* Long longs must not be split between registers and stack */
       if ((GET_MODE_CLASS (mode) != MODE_FLOAT || TARGET_SOFT_FLOAT)
 	  && type && !AGGREGATE_TYPE_P (type)
-	  && cum->words < GP_ARG_NUM_REG
-	  && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
+	  && cum->words - cum->sysv_fwords < GP_ARG_NUM_REG
+	  && cum->words - cum->sysv_fwords + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
 	{
-	  cum->words = GP_ARG_NUM_REG;
+	  cum->words = GP_ARG_NUM_REG + cum->sysv_fwords;
 	}
 
       /* Aggregates get passed as pointers */
@@ -1399,7 +1405,11 @@ function_arg_advance (cum, mode, type, n
 	cum->fregno++;
 
       else
-	cum->words += RS6000_ARG_SIZE (mode, type, 1);
+	{ 
+	  cum->words += RS6000_ARG_SIZE (mode, type, 1);
+	  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+	    cum->sysv_fwords += RS6000_ARG_SIZE (mode, type, 1);
+	}
     }
   else
     if (named)
@@ -1411,8 +1421,8 @@ function_arg_advance (cum, mode, type, n
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr,
-	     "function_adv: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
-	     cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+	     "function_adv: words = %2d, sysv_fwords = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
+	     cum->words, cum->sysv_fwords, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
 }
 
 /* Determine where to put an argument to a function.
@@ -1451,8 +1461,8 @@ function_arg (cum, mode, type, named)
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr,
-	     "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
-	     cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+	     "function_arg: words = %2d, sysv_fwords = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
+	     cum->words, cum->sysv_fwords, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
 
   /* Return a marker to indicate whether CR1 needs to set or clear the bit that V.4
      uses to say fp args were passed in registers.  Assume that we don't need the
@@ -1522,14 +1532,14 @@ function_arg (cum, mode, type, named)
   /* Long longs won't be split between register and stack;
      FP arguments get passed on the stack if they didn't get a register.  */
   else if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) &&
-	   (align_words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG
+	   (align_words - cum->sysv_fwords + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG
 	    || (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)))
     {
       return NULL_RTX;
     }
 
-  else if (align_words < GP_ARG_NUM_REG)
-    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+  else if (align_words - cum->sysv_fwords < GP_ARG_NUM_REG)
+    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words - cum->sysv_fwords);
 
   return NULL_RTX;
 }
@@ -1626,21 +1636,24 @@ setup_incoming_varargs (cum, mode, type,
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr,
-	     "setup_vararg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, no_rtl= %d\n",
-	     cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), no_rtl);
+	     "setup_vararg: words = %2d, sysv_fwords = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, no_rtl= %d\n",
+	     cum->words, cum->sysv_fwords, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), no_rtl);
 
   if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
     {
       rs6000_sysv_varargs_p = 1;
       if (! no_rtl)
-	save_area = plus_constant (frame_pointer_rtx, RS6000_VARARGS_OFFSET);
+	{
+	  save_area = plus_constant (virtual_stack_vars_rtx, -RS6000_VARARGS_SIZE);
+	  (rtx) cum->save_area = save_area;
+	}
     }
   else
     rs6000_sysv_varargs_p = 0;
 
-  if (cum->words < 8)
+  if (cum->words - cum->sysv_fwords < 8)
     {
-      int first_reg_offset = cum->words;
+      int first_reg_offset = cum->words - cum->sysv_fwords;
 
       if (MUST_PASS_IN_STACK (mode, type))
 	first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);


More information about the Linuxppc-dev mailing list