x86-64: Add vararg ABI tests

Message ID 20190516201015.21850-1-hjl.tools@gmail.com
State New
Headers show
Series
  • x86-64: Add vararg ABI tests
Related show

Commit Message

H.J. Lu May 16, 2019, 8:10 p.m.
We can scan stack for return address to get vector arguments passed on
stack.

	* gcc.target/x86_64/abi/test_varargs-m128.c: New file.
	* gcc.target/x86_64/abi/avx/test_varargs-m256.c: Likewise.
	* gcc.target/x86_64/abi/avx512f/test_varargs-m512.c: Likewise.
---
 .../x86_64/abi/avx/test_varargs-m256.c        | 102 +++++++++++++++++
 .../x86_64/abi/avx512f/test_varargs-m512.c    | 102 +++++++++++++++++
 .../gcc.target/x86_64/abi/test_varargs-m128.c | 108 ++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c

-- 
2.20.1

Comments

Uros Bizjak May 17, 2019, 7:08 a.m. | #1
On Thu, May 16, 2019 at 10:10 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> We can scan stack for return address to get vector arguments passed on

> stack.

>

>         * gcc.target/x86_64/abi/test_varargs-m128.c: New file.

>         * gcc.target/x86_64/abi/avx/test_varargs-m256.c: Likewise.

>         * gcc.target/x86_64/abi/avx512f/test_varargs-m512.c: Likewise.


Bootstrapped and regression tested on which target? Does x32 passes the test?

> +  /* Check __m256 arguments passed on stack.  */

> +  argp = (__m256 *) (((char *) fp) + 8);


It took me a while to figure out that RA slot is skipped here. Please
add some comment, maybe:

  /* Skip return address stack slot.  */
  argp = (__m256 *) (((char *) fp) + 8);

  /* Check __m256 arguments passed on stack.  */
  compare (values.i4, argp[0], __m256);

Uros.

> ---

>  .../x86_64/abi/avx/test_varargs-m256.c        | 102 +++++++++++++++++

>  .../x86_64/abi/avx512f/test_varargs-m512.c    | 102 +++++++++++++++++

>  .../gcc.target/x86_64/abi/test_varargs-m128.c | 108 ++++++++++++++++++

>  3 files changed, 312 insertions(+)

>  create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c

>  create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c

>  create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c

>

> diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c

> new file mode 100644

> index 00000000000..d1bcf865487

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c

> @@ -0,0 +1,102 @@

> +/* Test variable number of 256-bit vector arguments passed to functions.  */

> +

> +#include <stdio.h>

> +#include "avx-check.h"

> +#include "args.h"

> +

> +struct IntegerRegisters iregs;

> +struct FloatRegisters fregs;

> +

> +/* This struct holds values for argument checking.  */

> +struct

> +{

> +  YMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;

> +} values;

> +

> +char *pass;

> +int failed = 0;

> +

> +#undef assert

> +#define assert(c) do { \

> +  if (!(c)) {failed++; printf ("failed %s\n", pass); } \

> +} while (0)

> +

> +#define compare(X1,X2,T) do { \

> +  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \

> +} while (0)

> +

> +void

> +fun_check_passing_m256_varargs (__m256 i0, __m256 i1, __m256 i2,

> +                               __m256 i3, ...)

> +{

> +  /* Check argument values.  */

> +  void **fp = __builtin_frame_address (0);

> +  void *ra = __builtin_return_address (0);

> +  __m256 *argp;

> +

> +  compare (values.i0, i0, __m256);

> +  compare (values.i1, i1, __m256);

> +  compare (values.i2, i2, __m256);

> +  compare (values.i3, i3, __m256);

> +

> +  /* Get the pointer to the return address on stack.  */

> +  while (*fp != ra)

> +    fp++;

> +

> +  /* Check __m256 arguments passed on stack.  */

> +  argp = (__m256 *) (((char *) fp) + 8);

> +  compare (values.i4, argp[0], __m256);

> +  compare (values.i5, argp[1], __m256);

> +  compare (values.i6, argp[2], __m256);

> +  compare (values.i7, argp[3], __m256);

> +  compare (values.i8, argp[4], __m256);

> +  compare (values.i9, argp[5], __m256);

> +

> +  /* Check register contents.  */

> +  compare (fregs.ymm0, ymm_regs[0], __m256);

> +  compare (fregs.ymm1, ymm_regs[1], __m256);

> +  compare (fregs.ymm2, ymm_regs[2], __m256);

> +  compare (fregs.ymm3, ymm_regs[3], __m256);

> +}

> +

> +#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \

> +                                     _i6, _i7, _i8, _i9, \

> +                                     _func, TYPE) \

> +  values.i0.TYPE[0] = _i0; \

> +  values.i1.TYPE[0] = _i1; \

> +  values.i2.TYPE[0] = _i2; \

> +  values.i3.TYPE[0] = _i3; \

> +  values.i4.TYPE[0] = _i4; \

> +  values.i5.TYPE[0] = _i5; \

> +  values.i6.TYPE[0] = _i6; \

> +  values.i7.TYPE[0] = _i7; \

> +  values.i8.TYPE[0] = _i8; \

> +  values.i9.TYPE[0] = _i9; \

> +  clear_struct_registers; \

> +  fregs.F0.TYPE[0] = _i0; \

> +  fregs.F1.TYPE[0] = _i1; \

> +  fregs.F2.TYPE[0] = _i2; \

> +  fregs.F3.TYPE[0] = _i3; \

> +  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);

> +

> +void

> +test_m256_varargs (void)

> +{

> +  __m256 x[10];

> +  int i;

> +  for (i = 0; i < 10; i++)

> +    x[i] = (__m256){32+i, 0, 0, 0, 0, 0, 0, 0};

> +  pass = "m256-varargs";

> +  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],

> +                                x[6], x[7], x[8], x[9],

> +                                fun_check_passing_m256_varargs,

> +                                _m256);

> +}

> +

> +void

> +avx_test (void)

> +{

> +  test_m256_varargs ();

> +  if (failed)

> +    abort ();

> +}

> diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c

> new file mode 100644

> index 00000000000..328f76de3df

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c

> @@ -0,0 +1,102 @@

> +/* Test variable number of 512-bit vector arguments passed to functions.  */

> +

> +#include <stdio.h>

> +#include "avx512f-check.h"

> +#include "args.h"

> +

> +struct IntegerRegisters iregs;

> +struct FloatRegisters fregs;

> +

> +/* This struct holds values for argument checking.  */

> +struct

> +{

> +  ZMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;

> +} values;

> +

> +char *pass;

> +int failed = 0;

> +

> +#undef assert

> +#define assert(c) do { \

> +  if (!(c)) {failed++; printf ("failed %s\n", pass); } \

> +} while (0)

> +

> +#define compare(X1,X2,T) do { \

> +  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \

> +} while (0)

> +

> +void

> +fun_check_passing_m512_varargs (__m512 i0, __m512 i1, __m512 i2,

> +                               __m512 i3, ...)

> +{

> +  /* Check argument values.  */

> +  void **fp = __builtin_frame_address (0);

> +  void *ra = __builtin_return_address (0);

> +  __m512 *argp;

> +

> +  compare (values.i0, i0, __m512);

> +  compare (values.i1, i1, __m512);

> +  compare (values.i2, i2, __m512);

> +  compare (values.i3, i3, __m512);

> +

> +  /* Get the pointer to the return address on stack.  */

> +  while (*fp != ra)

> +    fp++;

> +

> +  /* Check __m512 arguments passed on stack.  */

> +  argp = (__m512 *)(((char *) fp) + 8);

> +  compare (values.i4, argp[0], __m512);

> +  compare (values.i5, argp[1], __m512);

> +  compare (values.i6, argp[2], __m512);

> +  compare (values.i7, argp[3], __m512);

> +  compare (values.i8, argp[4], __m512);

> +  compare (values.i9, argp[5], __m512);

> +

> +  /* Check register contents.  */

> +  compare (fregs.zmm0, zmm_regs[0], __m512);

> +  compare (fregs.zmm1, zmm_regs[1], __m512);

> +  compare (fregs.zmm2, zmm_regs[2], __m512);

> +  compare (fregs.zmm3, zmm_regs[3], __m512);

> +}

> +

> +#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \

> +                                     _i6, _i7, _i8, _i9, \

> +                                     _func, TYPE) \

> +  values.i0.TYPE[0] = _i0; \

> +  values.i1.TYPE[0] = _i1; \

> +  values.i2.TYPE[0] = _i2; \

> +  values.i3.TYPE[0] = _i3; \

> +  values.i4.TYPE[0] = _i4; \

> +  values.i5.TYPE[0] = _i5; \

> +  values.i6.TYPE[0] = _i6; \

> +  values.i7.TYPE[0] = _i7; \

> +  values.i8.TYPE[0] = _i8; \

> +  values.i9.TYPE[0] = _i9; \

> +  clear_struct_registers; \

> +  fregs.F0.TYPE[0] = _i0; \

> +  fregs.F1.TYPE[0] = _i1; \

> +  fregs.F2.TYPE[0] = _i2; \

> +  fregs.F3.TYPE[0] = _i3; \

> +  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);

> +

> +void

> +test_m512_varargs (void)

> +{

> +  __m512 x[10];

> +  int i;

> +  for (i = 0; i < 10; i++)

> +    x[i] = (__m512){32+i, 0, 0, 0, 0, 0, 0, 0};

> +  pass = "m512-varargs";

> +  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],

> +                                x[6], x[7], x[8], x[9],

> +                                fun_check_passing_m512_varargs,

> +                                _m512);

> +}

> +

> +void

> +avx512f_test (void)

> +{

> +  test_m512_varargs ();

> +  if (failed)

> +    abort ();

> +}

> diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c

> new file mode 100644

> index 00000000000..b6359b52597

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c

> @@ -0,0 +1,108 @@

> +/* Test variable number of 128-bit vector arguments passed to functions.  */

> +

> +#include <stdio.h>

> +#include "defines.h"

> +#include "macros.h"

> +#include "args.h"

> +

> +struct IntegerRegisters iregs;

> +struct FloatRegisters fregs;

> +

> +/* This struct holds values for argument checking.  */

> +struct

> +{

> +  XMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;

> +} values;

> +

> +char *pass;

> +int failed = 0;

> +

> +#undef assert

> +#define assert(c) do { \

> +  if (!(c)) {failed++; printf ("failed %s\n", pass); } \

> +} while (0)

> +

> +#define compare(X1,X2,T) do { \

> +  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \

> +} while (0)

> +

> +void

> +fun_check_passing_m128_varargs (__m128 i0, __m128 i1, __m128 i2,

> +                               __m128 i3, ...)

> +{

> +  /* Check argument values.  */

> +  void **fp = __builtin_frame_address (0);

> +  void *ra = __builtin_return_address (0);

> +  __m128 *argp;

> +

> +  compare (values.i0, i0, __m128);

> +  compare (values.i1, i1, __m128);

> +  compare (values.i2, i2, __m128);

> +  compare (values.i3, i3, __m128);

> +

> +  /* Get the pointer to the return address on stack.  */

> +  while (*fp != ra)

> +    fp++;

> +

> +  /* Check __m128 arguments passed on stack.  */

> +  argp = (__m128 *) (((char *) fp) + 8);

> +  compare (values.i8, argp[0], __m128);

> +  compare (values.i9, argp[1], __m128);

> +

> +  /* Check register contents.  */

> +  compare (fregs.xmm0, xmm_regs[0], __m128);

> +  compare (fregs.xmm1, xmm_regs[1], __m128);

> +  compare (fregs.xmm2, xmm_regs[2], __m128);

> +  compare (fregs.xmm3, xmm_regs[3], __m128);

> +  compare (fregs.xmm4, xmm_regs[4], __m128);

> +  compare (fregs.xmm5, xmm_regs[5], __m128);

> +  compare (fregs.xmm6, xmm_regs[6], __m128);

> +  compare (fregs.xmm7, xmm_regs[7], __m128);

> +}

> +

> +#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \

> +                                     _i6, _i7, _i8, _i9, \

> +                                     _func, TYPE) \

> +  values.i0.TYPE[0] = _i0; \

> +  values.i1.TYPE[0] = _i1; \

> +  values.i2.TYPE[0] = _i2; \

> +  values.i3.TYPE[0] = _i3; \

> +  values.i4.TYPE[0] = _i4; \

> +  values.i5.TYPE[0] = _i5; \

> +  values.i6.TYPE[0] = _i6; \

> +  values.i7.TYPE[0] = _i7; \

> +  values.i8.TYPE[0] = _i8; \

> +  values.i9.TYPE[0] = _i9; \

> +  clear_float_registers; \

> +  fregs.F0.TYPE[0] = _i0; \

> +  fregs.F1.TYPE[0] = _i1; \

> +  fregs.F2.TYPE[0] = _i2; \

> +  fregs.F3.TYPE[0] = _i3; \

> +  fregs.F4.TYPE[0] = _i4; \

> +  fregs.F5.TYPE[0] = _i5; \

> +  fregs.F6.TYPE[0] = _i6; \

> +  fregs.F7.TYPE[0] = _i7; \

> +  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);

> +

> +void

> +test_m128_varargs (void)

> +{

> +  __m128 x[10];

> +  int i;

> +  for (i = 0; i < 10; i++)

> +    x[i] = (__m128){32+i, 0, 0, 0};

> +  pass = "m128-varargs";

> +  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],

> +                                x[6], x[7], x[8], x[9],

> +                                fun_check_passing_m128_varargs,

> +                                _m128);

> +}

> +

> +int

> +main (void)

> +{

> +  test_m128_varargs ();

> +  if (failed)

> +    abort ();

> +  return 0;

> +}

> --

> 2.20.1

>
H.J. Lu May 17, 2019, 3:04 p.m. | #2
On Fri, May 17, 2019 at 12:08 AM Uros Bizjak <ubizjak@gmail.com> wrote:
>

> On Thu, May 16, 2019 at 10:10 PM H.J. Lu <hjl.tools@gmail.com> wrote:

> >

> > We can scan stack for return address to get vector arguments passed on

> > stack.

> >

> >         * gcc.target/x86_64/abi/test_varargs-m128.c: New file.

> >         * gcc.target/x86_64/abi/avx/test_varargs-m256.c: Likewise.

> >         * gcc.target/x86_64/abi/avx512f/test_varargs-m512.c: Likewise.

>

> Bootstrapped and regression tested on which target? Does x32 passes the test?


Tested on Linux/x86-64 and Linux/x32.

> > +  /* Check __m256 arguments passed on stack.  */

> > +  argp = (__m256 *) (((char *) fp) + 8);

>

> It took me a while to figure out that RA slot is skipped here. Please

> add some comment, maybe:

>

>   /* Skip return address stack slot.  */

>   argp = (__m256 *) (((char *) fp) + 8);

>

>   /* Check __m256 arguments passed on stack.  */

>   compare (values.i4, argp[0], __m256);

>


Updated.

Here is the updated patch.   OK for trunk?

Thanks.

-- 
H.J.
From 4a9ab6e9d543dc921e00ef39d24e00f04f8450a0 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 16 May 2019 11:31:40 -0700
Subject: [PATCH] x86-64: Add vararg ABI tests

We can scan stack for return address to get vector arguments passed on
stack.

Tested on Linux/x86-64 and Linux/x32.

	* gcc.target/x86_64/abi/test_varargs-m128.c: New file.
	* gcc.target/x86_64/abi/avx/test_varargs-m256.c: Likewise.
	* gcc.target/x86_64/abi/avx512f/test_varargs-m512.c: Likewise.
---
 .../x86_64/abi/avx/test_varargs-m256.c        | 104 +++++++++++++++++
 .../x86_64/abi/avx512f/test_varargs-m512.c    | 104 +++++++++++++++++
 .../gcc.target/x86_64/abi/test_varargs-m128.c | 110 ++++++++++++++++++
 3 files changed, 318 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c

diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
new file mode 100644
index 00000000000..0c6d61f072f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
@@ -0,0 +1,104 @@
+/* Test variable number of 256-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "avx-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  YMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m256_varargs (__m256 i0, __m256 i1, __m256 i2,
+				__m256 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m256 *argp;
+
+  compare (values.i0, i0, __m256);
+  compare (values.i1, i1, __m256);
+  compare (values.i2, i2, __m256);
+  compare (values.i3, i3, __m256);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Skip the return address stack slot.  */
+  argp = (__m256 *) (((char *) fp) + 8);
+
+  /* Check __m256 arguments passed on stack.  */
+  compare (values.i4, argp[0], __m256);
+  compare (values.i5, argp[1], __m256);
+  compare (values.i6, argp[2], __m256);
+  compare (values.i7, argp[3], __m256);
+  compare (values.i8, argp[4], __m256);
+  compare (values.i9, argp[5], __m256);
+
+  /* Check register contents.  */
+  compare (fregs.ymm0, ymm_regs[0], __m256);
+  compare (fregs.ymm1, ymm_regs[1], __m256);
+  compare (fregs.ymm2, ymm_regs[2], __m256);
+  compare (fregs.ymm3, ymm_regs[3], __m256);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_struct_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m256_varargs (void)
+{
+  __m256 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m256){32+i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m256-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m256_varargs,
+				 _m256);
+}
+
+void
+avx_test (void)
+{
+  test_m256_varargs ();
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
new file mode 100644
index 00000000000..b2ba0e5ab22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
@@ -0,0 +1,104 @@
+/* Test variable number of 512-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "avx512f-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  ZMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m512_varargs (__m512 i0, __m512 i1, __m512 i2,
+				__m512 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m512 *argp;
+
+  compare (values.i0, i0, __m512);
+  compare (values.i1, i1, __m512);
+  compare (values.i2, i2, __m512);
+  compare (values.i3, i3, __m512);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Skip the return address stack slot.  */
+  argp = (__m512 *)(((char *) fp) + 8);
+
+  /* Check __m512 arguments passed on stack.  */
+  compare (values.i4, argp[0], __m512);
+  compare (values.i5, argp[1], __m512);
+  compare (values.i6, argp[2], __m512);
+  compare (values.i7, argp[3], __m512);
+  compare (values.i8, argp[4], __m512);
+  compare (values.i9, argp[5], __m512);
+
+  /* Check register contents.  */
+  compare (fregs.zmm0, zmm_regs[0], __m512);
+  compare (fregs.zmm1, zmm_regs[1], __m512);
+  compare (fregs.zmm2, zmm_regs[2], __m512);
+  compare (fregs.zmm3, zmm_regs[3], __m512);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_struct_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m512_varargs (void)
+{
+  __m512 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m512){32+i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m512-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m512_varargs,
+				 _m512);
+}
+
+void
+avx512f_test (void)
+{
+  test_m512_varargs ();
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c
new file mode 100644
index 00000000000..30757687439
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c
@@ -0,0 +1,110 @@
+/* Test variable number of 128-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "defines.h"
+#include "macros.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  XMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m128_varargs (__m128 i0, __m128 i1, __m128 i2,
+				__m128 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m128 *argp;
+
+  compare (values.i0, i0, __m128);
+  compare (values.i1, i1, __m128);
+  compare (values.i2, i2, __m128);
+  compare (values.i3, i3, __m128);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Skip the return address stack slot.  */
+  argp = (__m128 *) (((char *) fp) + 8);
+
+  /* Check __m128 arguments passed on stack.  */
+  compare (values.i8, argp[0], __m128);
+  compare (values.i9, argp[1], __m128);
+
+  /* Check register contents.  */
+  compare (fregs.xmm0, xmm_regs[0], __m128);
+  compare (fregs.xmm1, xmm_regs[1], __m128);
+  compare (fregs.xmm2, xmm_regs[2], __m128);
+  compare (fregs.xmm3, xmm_regs[3], __m128);
+  compare (fregs.xmm4, xmm_regs[4], __m128);
+  compare (fregs.xmm5, xmm_regs[5], __m128);
+  compare (fregs.xmm6, xmm_regs[6], __m128);
+  compare (fregs.xmm7, xmm_regs[7], __m128);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_float_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  fregs.F4.TYPE[0] = _i4; \
+  fregs.F5.TYPE[0] = _i5; \
+  fregs.F6.TYPE[0] = _i6; \
+  fregs.F7.TYPE[0] = _i7; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m128_varargs (void)
+{
+  __m128 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m128){32+i, 0, 0, 0};
+  pass = "m128-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m128_varargs,
+				 _m128);
+}
+
+int
+main (void)
+{
+  test_m128_varargs ();
+  if (failed)
+    abort ();
+  return 0;
+}
Uros Bizjak May 17, 2019, 3:44 p.m. | #3
On Fri, May 17, 2019 at 5:05 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Fri, May 17, 2019 at 12:08 AM Uros Bizjak <ubizjak@gmail.com> wrote:

> >

> > On Thu, May 16, 2019 at 10:10 PM H.J. Lu <hjl.tools@gmail.com> wrote:

> > >

> > > We can scan stack for return address to get vector arguments passed on

> > > stack.

> > >

> > >         * gcc.target/x86_64/abi/test_varargs-m128.c: New file.

> > >         * gcc.target/x86_64/abi/avx/test_varargs-m256.c: Likewise.

> > >         * gcc.target/x86_64/abi/avx512f/test_varargs-m512.c: Likewise.

> >

> > Bootstrapped and regression tested on which target? Does x32 passes the test?

>

> Tested on Linux/x86-64 and Linux/x32.

>

> > > +  /* Check __m256 arguments passed on stack.  */

> > > +  argp = (__m256 *) (((char *) fp) + 8);

> >

> > It took me a while to figure out that RA slot is skipped here. Please

> > add some comment, maybe:

> >

> >   /* Skip return address stack slot.  */

> >   argp = (__m256 *) (((char *) fp) + 8);

> >

> >   /* Check __m256 arguments passed on stack.  */

> >   compare (values.i4, argp[0], __m256);

> >

>

> Updated.

>

> Here is the updated patch.   OK for trunk?


LGTM.

Thanks,
Uros.

Patch

diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
new file mode 100644
index 00000000000..d1bcf865487
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_varargs-m256.c
@@ -0,0 +1,102 @@ 
+/* Test variable number of 256-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "avx-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  YMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m256_varargs (__m256 i0, __m256 i1, __m256 i2,
+				__m256 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m256 *argp;
+
+  compare (values.i0, i0, __m256);
+  compare (values.i1, i1, __m256);
+  compare (values.i2, i2, __m256);
+  compare (values.i3, i3, __m256);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Check __m256 arguments passed on stack.  */
+  argp = (__m256 *) (((char *) fp) + 8);
+  compare (values.i4, argp[0], __m256);
+  compare (values.i5, argp[1], __m256);
+  compare (values.i6, argp[2], __m256);
+  compare (values.i7, argp[3], __m256);
+  compare (values.i8, argp[4], __m256);
+  compare (values.i9, argp[5], __m256);
+
+  /* Check register contents.  */
+  compare (fregs.ymm0, ymm_regs[0], __m256);
+  compare (fregs.ymm1, ymm_regs[1], __m256);
+  compare (fregs.ymm2, ymm_regs[2], __m256);
+  compare (fregs.ymm3, ymm_regs[3], __m256);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_struct_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m256_varargs (void)
+{
+  __m256 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m256){32+i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m256-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m256_varargs,
+				 _m256);
+}
+
+void
+avx_test (void)
+{
+  test_m256_varargs ();
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
new file mode 100644
index 00000000000..328f76de3df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512f/test_varargs-m512.c
@@ -0,0 +1,102 @@ 
+/* Test variable number of 512-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "avx512f-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  ZMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m512_varargs (__m512 i0, __m512 i1, __m512 i2,
+				__m512 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m512 *argp;
+
+  compare (values.i0, i0, __m512);
+  compare (values.i1, i1, __m512);
+  compare (values.i2, i2, __m512);
+  compare (values.i3, i3, __m512);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Check __m512 arguments passed on stack.  */
+  argp = (__m512 *)(((char *) fp) + 8);
+  compare (values.i4, argp[0], __m512);
+  compare (values.i5, argp[1], __m512);
+  compare (values.i6, argp[2], __m512);
+  compare (values.i7, argp[3], __m512);
+  compare (values.i8, argp[4], __m512);
+  compare (values.i9, argp[5], __m512);
+
+  /* Check register contents.  */
+  compare (fregs.zmm0, zmm_regs[0], __m512);
+  compare (fregs.zmm1, zmm_regs[1], __m512);
+  compare (fregs.zmm2, zmm_regs[2], __m512);
+  compare (fregs.zmm3, zmm_regs[3], __m512);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_struct_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m512_varargs (void)
+{
+  __m512 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m512){32+i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m512-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m512_varargs,
+				 _m512);
+}
+
+void
+avx512f_test (void)
+{
+  test_m512_varargs ();
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c
new file mode 100644
index 00000000000..b6359b52597
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/test_varargs-m128.c
@@ -0,0 +1,108 @@ 
+/* Test variable number of 128-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "defines.h"
+#include "macros.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+
+/* This struct holds values for argument checking.  */
+struct 
+{
+  XMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+} values;
+
+char *pass;
+int failed = 0;
+
+#undef assert
+#define assert(c) do { \
+  if (!(c)) {failed++; printf ("failed %s\n", pass); } \
+} while (0)
+
+#define compare(X1,X2,T) do { \
+  assert (memcmp (&X1, &X2, sizeof (T)) == 0); \
+} while (0)
+
+void
+fun_check_passing_m128_varargs (__m128 i0, __m128 i1, __m128 i2,
+				__m128 i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m128 *argp;
+
+  compare (values.i0, i0, __m128);
+  compare (values.i1, i1, __m128);
+  compare (values.i2, i2, __m128);
+  compare (values.i3, i3, __m128);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Check __m128 arguments passed on stack.  */
+  argp = (__m128 *) (((char *) fp) + 8);
+  compare (values.i8, argp[0], __m128);
+  compare (values.i9, argp[1], __m128);
+
+  /* Check register contents.  */
+  compare (fregs.xmm0, xmm_regs[0], __m128);
+  compare (fregs.xmm1, xmm_regs[1], __m128);
+  compare (fregs.xmm2, xmm_regs[2], __m128);
+  compare (fregs.xmm3, xmm_regs[3], __m128);
+  compare (fregs.xmm4, xmm_regs[4], __m128);
+  compare (fregs.xmm5, xmm_regs[5], __m128);
+  compare (fregs.xmm6, xmm_regs[6], __m128);
+  compare (fregs.xmm7, xmm_regs[7], __m128);
+}
+
+#define def_check_int_passing_varargs(_i0, _i1, _i2, _i3, _i4, _i5, \
+				      _i6, _i7, _i8, _i9, \
+				      _func, TYPE) \
+  values.i0.TYPE[0] = _i0; \
+  values.i1.TYPE[0] = _i1; \
+  values.i2.TYPE[0] = _i2; \
+  values.i3.TYPE[0] = _i3; \
+  values.i4.TYPE[0] = _i4; \
+  values.i5.TYPE[0] = _i5; \
+  values.i6.TYPE[0] = _i6; \
+  values.i7.TYPE[0] = _i7; \
+  values.i8.TYPE[0] = _i8; \
+  values.i9.TYPE[0] = _i9; \
+  clear_float_registers; \
+  fregs.F0.TYPE[0] = _i0; \
+  fregs.F1.TYPE[0] = _i1; \
+  fregs.F2.TYPE[0] = _i2; \
+  fregs.F3.TYPE[0] = _i3; \
+  fregs.F4.TYPE[0] = _i4; \
+  fregs.F5.TYPE[0] = _i5; \
+  fregs.F6.TYPE[0] = _i6; \
+  fregs.F7.TYPE[0] = _i7; \
+  WRAP_CALL(_func) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9);
+
+void
+test_m128_varargs (void)
+{
+  __m128 x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m128){32+i, 0, 0, 0};
+  pass = "m128-varargs";
+  def_check_int_passing_varargs (x[0], x[1], x[2], x[3], x[4], x[5],
+				 x[6], x[7], x[8], x[9],
+				 fun_check_passing_m128_varargs,
+				 _m128);
+}
+
+int
+main (void)
+{
+  test_m128_varargs ();
+  if (failed)
+    abort ();
+  return 0;
+}