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] PPC64 ABI conformance


Alan Modra wrote:
> > Hello,
> >       current ppc64 compiler does not conform to the new 64bit ABI:
> > Out of ABI document version 1.7:
> >
> >   * If there is no known function prototype for a callee, or if the
> >     function prototype for a callee contains an ellipsis and the
> >     argument value is not part of the fixed arguments described by the
> >     prototype, then floating point and vector values are passed
according
> >     to the following rules for non-floating, non-vector types.  In the
> >     case of no known prototype this may result in two copies of
floating
> >     and vector argument values being passed.
[snip]
> > @@ -3923,8 +3923,9 @@ function_arg_advance (CUMULATIVE_ARGS *c
> >
> >        /* In variable-argument functions, vector arguments get GPRs
allocated
> >        even if they are going to be passed in a vector register.  */
> > -      if (cum->stdarg && DEFAULT_ABI != ABI_V4)
> > -     {
> > +      if (DEFAULT_ABI != ABI_V4
> > +          && (cum->stdarg || (TARGET_64BIT && !cum->prototype)))
> > +        {
> >         int align;
> >
> >         /* Vector parameters must be 16-byte aligned.  This places

> I don't think this will do as the PowerPC64 Linux ABI intends.  The
> fixed args of a stdarg function call are supposed to be passed the same
> way as args of an identical function without ellipsis.  So any place
> that tests cum->stdarg in function_arg_advance should be viewed with
> suspicion.  Also, vector args take space in the parameter save area
> just as floating point args do.  The ABI gives this example for
> a mix of floating point args and other arg types:

Yes, you are right.

> typedef struct {
>   int    a;
>   double dd;
> } sparm;
> sparm   s, t;
> int     c, d, e;
> long double ld;
> double  ff, gg, hh;

> x = func(c, ff, d, ld, s, gg, t, e, hh);

> Parameter     Register     Offset in parameter save area
> c             r3           0-7    (not stored in parameter save area)
> ff            f1           8-15   (not stored)
> d             r5           16-23  (not stored)
> ld            f2,f3        24-39  (not stored)
> s             r8,r9        40-55  (not stored)
> gg            f4           56-63  (not stored)
> t             (none)       64-79  (stored in parameter save area)
> e             (none)       80-87  (stored)
> hh            f5           88-95  (not stored)

> This example assumes a prototype is in scope for "func".  Notice how r4,
> r6 and r7 are not used to pass values.  f1, f2 and f3 in this instance
> "shadow" them.  Vector args should do the same.  Thus a call to
> "foo (vector int a, long b)" should pass a in v2 and b in r5.  A call
> to "bar (long a, vector float b, long c)" would pass a in r3, b in v2,
> and c in r7.

> From statements others have made, I believe this is different to the AIX
> (and Darwin?) scheme, where vectors are passed as if they were specified
> last in the argument list.

Yes, this was stated in the altivec pim document for ALTIVEC. I thought,
we wanted to change that for all 64 bit ABIs.
David, Geoff, could you comment on this. If this is different on AIX64
and Darwin 64 bit, is there a way to change it ?

> I think you want the following (but I'm not sure whether the original
> test was correct for the other ABIs!):

>       /* PowerPC64 Linux allocates GPRs for a vector argument even if
>             it is going to be passed in a vector register.  Darwin and
>             AIX do the same for variable-argument functions.  */
>      if ((TARGET_ELF && TARGET_64BIT)
>              || (cum->stdarg && DEFAULT_ABI != ABI_V4))

Incorporated it into patch.

>[snip]
> > Testcase ppc64-abi-2.c:

> Could you please add a test here for a vector arg followed by integer
> args?

Done, added fcvi (char *s, vector int v, int i), 'i' should be
passed in GPRs 7, does it with patch (not without).

Bootstrap / test ongoing, OK to commit ?

      regards, Hartmut

ChangeLog

      * gcc/config/rs6000/rs6000.c (function_arg) Handle
      vector register special in function without prototype.
      (function_arg_advance): Vector parameters get always
      GPRs allocated for the linux64 target.

Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.580
diff -u -p -r1.580 rs6000.c
--- config/rs6000/rs6000.c    18 Jan 2004 15:45:51 -0000    1.580
+++ config/rs6000/rs6000.c    19 Jan 2004 07:57:15 -0000
@@ -3941,10 +3941,12 @@ function_arg_advance (CUMULATIVE_ARGS *c
       if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
      cum->vregno++;

-      /* In variable-argument functions, vector arguments get GPRs allocated
-      even if they are going to be passed in a vector register.  */
-      if (cum->stdarg && DEFAULT_ABI != ABI_V4)
-     {
+      /* PowerPC64 Linux allocates GPRs for a vector argument even if
+      it is going to be passed in a vector register.  Darwin
+      and AIX do the same for variable-argument functions.  */
+      if ((TARGET_ELF && TARGET_64BIT)
+              || (cum->stdarg && DEFAULT_ABI != ABI_V4))
+        {
        int align;

        /* Vector parameters must be 16-byte aligned.  This places
@@ -4248,7 +4250,32 @@ function_arg (CUMULATIVE_ARGS *cum, enum
     }

   if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
-    return gen_rtx_REG (mode, cum->vregno);
+    if (TARGET_64BIT && ! cum->prototype)
+      {
+       /* Vector parameters get passed in vector register
+          and also in GPRs or memory, in absence of prototype.  */
+       int align_words;
+       rtx slot;
+       align_words = (cum->words + 1) & ~1;
+
+       if (align_words >= GP_ARG_NUM_REG)
+         {
+           slot = NULL_RTX;
+         }
+       else
+         {
+           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+         }
+       return gen_rtx_PARALLEL (mode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              slot, const0_rtx),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (mode, cum->vregno),
+                                              const0_rtx)));
+      }
+    else
+      return gen_rtx_REG (mode, cum->vregno);
   else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
       if (named || abi == ABI_V4)


Testcase ppc-linux64-abi-1.c:

      /* { dg-do run { target powerpc64-*-linux* } } */
/* { dg-options "-O2 -fprofile -mprofile-kernel -maltivec -mabi=altivec" } */
#include <stdarg.h>
#include <signal.h>
#include <altivec.h>

/* Testcase to check for ABI compliance of parameter passing
   for the PowerPC64 Linux ABI.  */

void __attribute__((no_instrument_function))
sig_ill_handler (int sig)
{
    exit(0);
}

extern void abort (void);

typedef struct
{
  unsigned long gprs[8];
  double fprs[13];
  long pad;
  vector int vrs[12];
} reg_parms_t;

reg_parms_t gparms;

/* _mcount call is done on Linux ppc64 early in the prologue.
   my_mcount will provide a entry point _mcount,
   which will save all register to gparms.
   Note that _mcount need to restore lr to original value,
   therefor use ctr to return.
*/

void __attribute__((no_instrument_function))
my_mcount()
{
  asm volatile (".type  _mcount,@function\n\t"
            ".globl     _mcount\n\t"
            "_mcount:\n\t"
            "mflr 0\n\t"
            "mtctr 0\n\t"
            "ld 0,16(1)\n\t"
            "mtlr 0\n\t"
            "ld 11,gparms@got(2)\n\t"
            "std 3,0(11)\n\t"
            "std 4,8(11)\n\t"
            "std 5,16(11)\n\t"
            "std 6,24(11)\n\t"
            "std 7,32(11)\n\t"
            "std 8,40(11)\n\t"
            "std 9,48(11)\n\t"
            "std 10,56(11)\n\t"
            "stfd 1,64(11)\n\t"
            "stfd 2,72(11)\n\t"
            "stfd 3,80(11)\n\t"
            "stfd 4,88(11)\n\t"
            "stfd 5,96(11)\n\t"
            "stfd 6,104(11)\n\t"
            "stfd 7,112(11)\n\t"
            "stfd 8,120(11)\n\t"
            "stfd 9,128(11)\n\t"
            "stfd 10,136(11)\n\t"
            "stfd 11,144(11)\n\t"
            "stfd 12,152(11)\n\t"
            "stfd 13,160(11)\n\t"
            "li 3,176\n\t"
            "stvx 2,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 3,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 4,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 5,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 6,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 7,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 8,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 9,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 10,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 11,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 12,3,11\n\t"
            "addi 3,3,16\n\t"
            "stvx 13,3,11\n\t"
            "ld 3,0(11)\n\t"
            "bctr");
}

/* Stackframe structure relevant for parameter passing.  */
typedef union
{
  double d;
  unsigned long l;
  unsigned int i[2];
} parm_t;

typedef struct sf
{
  struct sf *backchain;
  long a1;
  long a2;
  long a3;
  long a4;
  long a5;
  parm_t slot[100];
} stack_frame_t;

typedef union
{
  unsigned int i[4];
  unsigned long l[2];
  vector int v;
} vector_int_t;

/* Paramter passing.
   s : gpr 3
   v : vpr 2
   i : gpr 6
*/
void __attribute__ ((noinline))
fcvi (char *s, vector int v, int i)
{
  reg_parms_t lparms = gparms;

  if (s != (char *) lparms.gprs[0])
    abort();

  if (!vec_all_eq (v, lparms.vrs[0]))
    abort ();

  if ((long) i != lparms.gprs[4])
    abort();
}
/* Paramter passing.
   s : gpr 3
   v : vpr 2
   w : vpr 3
*/

void __attribute__ ((noinline))
fcvv (char *s, vector int v, vector int w)
{
  vector int a, c = {6, 8, 10, 12};
  reg_parms_t lparms = gparms;

  if (s != (char *) lparms.gprs[0])
    abort();

  if (!vec_all_eq (v, lparms.vrs[0]))
    abort ();

  if (!vec_all_eq (w, lparms.vrs[1]))
    abort ();

  a = vec_add (v,w);

  if (!vec_all_eq (a, c))
    abort ();
}

/* Paramter passing.
   s : gpr 3
   i : gpr 4
   v : vpr 2
   w : vpr 3
*/
void __attribute__ ((noinline))
fcivv (char *s, int i, vector int v, vector int w)
{
  vector int a, c = {6, 8, 10, 12};
  reg_parms_t lparms = gparms;

  if (s != (char *) lparms.gprs[0])
    abort();

  if ((long) i != lparms.gprs[1])
    abort();

  if (!vec_all_eq (v, lparms.vrs[0]))
    abort ();

  if (!vec_all_eq (w, lparms.vrs[1]))
    abort ();

  a = vec_add (v,w);

  if (!vec_all_eq (a, c))
    abort ();
}

/* Paramter passing.
   s : gpr 3
   v : slot 2-3
   w : slot 4-5
*/

void __attribute__ ((noinline))
fcevv (char *s, ...)
{
  vector int a, c = {6, 8, 10, 12};
  vector int v,w;
  stack_frame_t *sp;
  reg_parms_t lparms = gparms;
  va_list arg;

  va_start (arg, s);

  if (s != (char *) lparms.gprs[0])
    abort();

  v = va_arg(arg, vector int);
  w = va_arg(arg, vector int);
  a = vec_add (v,w);

  if (!vec_all_eq (a, c))
    abort ();

  /* Go back one frame.  */
  sp = __builtin_frame_address(0);
  sp = sp->backchain;

  if (sp->slot[2].l != 0x100000002ULL
      || sp->slot[4].l != 0x500000006ULL)
    abort();
}

/* Paramter passing.
   s : gpr 3
   i : gpr 4
   j : gpr 5
   v : slot 4-5
   w : slot 6-7
*/
void __attribute__ ((noinline))
fciievv (char *s, int i, int j, ...)
{
  vector int a, c = {6, 8, 10, 12};
  vector int v,w;
  stack_frame_t *sp;
  reg_parms_t lparms = gparms;
  va_list arg;

  va_start (arg, j);

  if (s != (char *) lparms.gprs[0])
    abort();

  if ((long) i != lparms.gprs[1])
    abort();

  if ((long) j != lparms.gprs[2])
    abort();

  v = va_arg(arg, vector int);
  w = va_arg(arg, vector int);
  a = vec_add (v,w);

  if (!vec_all_eq (a, c))
    abort ();

  sp = __builtin_frame_address(0);
  sp = sp->backchain;

  if (sp->slot[4].l != 0x100000002ULL
      || sp->slot[6].l != 0x500000006ULL)
    abort();
}

void __attribute__ ((noinline))
fcvevv (char *s, vector int x, ...)
{
  vector int a, c = {7, 10, 13, 16};
  vector int v,w;
  stack_frame_t *sp;
  reg_parms_t lparms = gparms;
  va_list arg;

  va_start (arg, x);

  v = va_arg(arg, vector int);
  w = va_arg(arg, vector int);

  a = vec_add (v,w);
  a = vec_add (a, x);

  if (!vec_all_eq (a, c))
    abort ();

  sp = __builtin_frame_address(0);
  sp = sp->backchain;

  if (sp->slot[4].l != 0x100000002ULL
      || sp->slot[6].l != 0x500000006ULL)
    abort();
}

void fnp_cvvvv();

int __attribute__((no_instrument_function, noinline))
main1()
{
  char *s = "vv";
  vector int v = {1, 2, 3, 4};
  vector int w = {5, 6, 7, 8};

  fcvi (s, v, 2);
  fcvv (s, v, w);
  fnp_cvvvv (s, v, w, v, w);
  fcivv (s, 1, v, w);
  fcevv (s, v, w);
  fciievv (s, 1, 2, v, w);
  fcvevv (s, v, v, w);
  return 0;
}

int __attribute__((no_instrument_function))
main()
{
  /* Exit on systems without altivec.  */
  signal (SIGILL, sig_ill_handler);
  /* Altivec instruction, 'vor %v0,%v0,%v0'.  */
  asm volatile (".long 0x10000484");
  signal (SIGILL, SIG_DFL);

  return main1 ();
}

/* Paramter passing.
   Function called with no prototype.
   s : gpr 3
   v : vpr 2 gpr 5-6
   w : vpr 3 gpr 7-8
   x : vpr 4 gpr 9-10
   y : vpr 5 slot 8-9
*/
void
fnp_cvvvv (char *s, vector int v, vector int w,
         vector int x, vector int y)
{
  vector int a, c = {12, 16, 20, 24};
  reg_parms_t lparms = gparms;
  stack_frame_t *sp;
  vector_int_t v0, v1, v2, v3;

  if (s != (char *) lparms.gprs[0])
    abort();

  if (!vec_all_eq (v, lparms.vrs[0]))
    abort ();

  if (!vec_all_eq (w, lparms.vrs[1]))
    abort ();

  if (!vec_all_eq (x, lparms.vrs[2]))
    abort ();

  if (!vec_all_eq (y, lparms.vrs[3]))
    abort ();

  a = vec_add (v,w);
  a = vec_add (a,x);
  a = vec_add (a,y);

  if (!vec_all_eq (a, c))
    abort ();

  v0.v = lparms.vrs[0];
  v1.v = lparms.vrs[1];
  v2.v = lparms.vrs[2];
  v3.v = lparms.vrs[3];

  if (v0.l[0] != lparms.gprs[2])
    abort ();

  if (v0.l[1] != lparms.gprs[3])
    abort ();

  if (v1.l[0] != lparms.gprs[4])
    abort ();

  if (v1.l[1] != lparms.gprs[5])
    abort ();

  if (v2.l[0] != lparms.gprs[6])
    abort ();

  if (v2.l[1] != lparms.gprs[7])
    abort ();

  sp = __builtin_frame_address(0);
  sp = sp->backchain;

  if (sp->slot[8].l != v3.l[0])
    abort ();

  if (sp->slot[9].l != v3.l[1])
    abort ();
}



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