diff mbox series

[10/10] AVX512FP16: Add abi test for zmm

Message ID 20210721074347.7689-11-hongtao.liu@intel.com
State New
Headers show
Series Initial support for AVX512FP16 | expand

Commit Message

Liu, Hongtao July 21, 2021, 7:43 a.m. UTC
gcc/testsuite/ChangeLog:

	* gcc.target/x86_64/abi/avx512fp16/m512h/abi-avx512fp16-zmm.exp:
	New file.
	* gcc.target/x86_64/abi/avx512fp16/m512h/args.h: Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/asm-support.S: Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/avx512fp16-zmm-check.h:
	Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/test_m512_returning.c:
	Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_m512.c:
	Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_structs.c:
	Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_unions.c:
	Likewise.
	* gcc.target/x86_64/abi/avx512fp16/m512h/test_varargs-m512.c:
	Likewise.
---
 .../avx512fp16/m512h/abi-avx512fp16-zmm.exp   |  48 ++
 .../x86_64/abi/avx512fp16/m512h/args.h        | 186 ++++++++
 .../x86_64/abi/avx512fp16/m512h/asm-support.S |  97 ++++
 .../avx512fp16/m512h/avx512fp16-zmm-check.h   |   4 +
 .../avx512fp16/m512h/test_m512_returning.c    |  62 +++
 .../abi/avx512fp16/m512h/test_passing_m512.c  | 380 ++++++++++++++++
 .../avx512fp16/m512h/test_passing_structs.c   | 123 ++++++
 .../avx512fp16/m512h/test_passing_unions.c    | 415 ++++++++++++++++++
 .../abi/avx512fp16/m512h/test_varargs-m512.c  | 164 +++++++
 9 files changed, 1479 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/abi-avx512fp16-zmm.exp
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/args.h
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/asm-support.S
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/avx512fp16-zmm-check.h
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_m512_returning.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_m512.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_structs.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_unions.c
 create mode 100644 gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_varargs-m512.c
diff mbox series

Patch

diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/abi-avx512fp16-zmm.exp b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/abi-avx512fp16-zmm.exp
new file mode 100644
index 00000000000..33d24762788
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/abi-avx512fp16-zmm.exp
@@ -0,0 +1,48 @@ 
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# The x86-64 ABI testsuite needs one additional assembler file for most
+# testcases.  For simplicity we will just link it into each test.
+
+load_lib c-torture.exp
+load_lib target-supports.exp
+load_lib torture-options.exp
+load_lib clearcap.exp
+load_lib file-format.exp
+
+if { (![istarget x86_64-*-*] && ![istarget i?86-*-*])
+     || [is-effective-target ia32]
+     || [gcc_target_object_format] != "elf"
+     || ![is-effective-target avx512fp16] } then {
+  return
+}
+
+
+torture-init
+clearcap-init
+set-torture-options $C_TORTURE_OPTIONS
+set additional_flags "-W -Wall -Wno-abi -mavx512fp16"
+
+foreach src [lsort [glob -nocomplain $srcdir/$subdir/test_*.c]] {
+    if {[runtest_file_p $runtests $src]} {
+	c-torture-execute [list $src \
+				$srcdir/$subdir/asm-support.S] \
+				$additional_flags
+    }
+}
+
+clearcap-finish
+torture-finish
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/args.h b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/args.h
new file mode 100644
index 00000000000..ec89fae4597
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/args.h
@@ -0,0 +1,186 @@ 
+#ifndef INCLUDED_ARGS_H
+#define INCLUDED_ARGS_H
+
+#include <immintrin.h>
+#include <string.h>
+
+/* Assertion macro.  */
+#define assert(test) if (!(test)) abort()
+
+#ifdef __GNUC__
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+/* This defines the calling sequences for integers and floats.  */
+#define I0 rdi
+#define I1 rsi
+#define I2 rdx
+#define I3 rcx
+#define I4 r8
+#define I5 r9
+#define F0 zmm0
+#define F1 zmm1
+#define F2 zmm2
+#define F3 zmm3
+#define F4 zmm4
+#define F5 zmm5
+#define F6 zmm6
+#define F7 zmm7
+
+typedef union {
+  _Float16 __Float16[32];
+  float _float[16];
+  double _double[8];
+  long _long[8];
+  int _int[16];
+  unsigned long _ulong[8];
+  __m64 _m64[8];
+  __m128 _m128[4];
+  __m256 _m256[2];
+  __m512 _m512[1];
+  __m512h _m512h[1];
+} ZMM_T;
+
+typedef union {
+  float _float;
+  double _double;
+  long double _ldouble;
+  unsigned long _ulong[2];
+} X87_T;
+extern void (*callthis)(void);
+extern unsigned long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
+ZMM_T zmm_regs[32];
+X87_T x87_regs[8];
+extern volatile unsigned long volatile_var;
+extern void snapshot (void);
+extern void snapshot_ret (void);
+#define WRAP_CALL(N) \
+  (callthis = (void (*)()) (N), (typeof (&N)) snapshot)
+#define WRAP_RET(N) \
+  (callthis = (void (*)()) (N), (typeof (&N)) snapshot_ret)
+
+/* Clear all integer registers.  */
+#define clear_int_hardware_registers \
+  asm __volatile__ ("xor %%rax, %%rax\n\t" \
+		    "xor %%rbx, %%rbx\n\t" \
+		    "xor %%rcx, %%rcx\n\t" \
+		    "xor %%rdx, %%rdx\n\t" \
+		    "xor %%rsi, %%rsi\n\t" \
+		    "xor %%rdi, %%rdi\n\t" \
+		    "xor %%r8, %%r8\n\t" \
+		    "xor %%r9, %%r9\n\t" \
+		    "xor %%r10, %%r10\n\t" \
+		    "xor %%r11, %%r11\n\t" \
+		    "xor %%r12, %%r12\n\t" \
+		    "xor %%r13, %%r13\n\t" \
+		    "xor %%r14, %%r14\n\t" \
+		    "xor %%r15, %%r15\n\t" \
+		    ::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", \
+		    "r9", "r10", "r11", "r12", "r13", "r14", "r15");
+
+/* This is the list of registers available for passing arguments. Not all of
+   these are used or even really available.  */
+struct IntegerRegisters
+{
+  unsigned long rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15;
+};
+struct FloatRegisters
+{
+  double mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
+  long double st0, st1, st2, st3, st4, st5, st6, st7;
+  ZMM_T zmm0, zmm1, zmm2, zmm3, zmm4, zmm5, zmm6, zmm7, zmm8, zmm9,
+        zmm10, zmm11, zmm12, zmm13, zmm14, zmm15, zmm16, zmm17, zmm18,
+	zmm19, zmm20, zmm21, zmm22, zmm23, zmm24, zmm25, zmm26, zmm27,
+	zmm28, zmm29, zmm30, zmm31;
+};
+
+/* Implemented in scalarargs.c  */
+extern struct IntegerRegisters iregs;
+extern struct FloatRegisters fregs;
+extern unsigned int num_iregs, num_fregs;
+
+#define check_int_arguments do { \
+  assert (num_iregs <= 0 || iregs.I0 == I0); \
+  assert (num_iregs <= 1 || iregs.I1 == I1); \
+  assert (num_iregs <= 2 || iregs.I2 == I2); \
+  assert (num_iregs <= 3 || iregs.I3 == I3); \
+  assert (num_iregs <= 4 || iregs.I4 == I4); \
+  assert (num_iregs <= 5 || iregs.I5 == I5); \
+  } while (0)
+
+#define check_char_arguments check_int_arguments
+#define check_short_arguments check_int_arguments
+#define check_long_arguments check_int_arguments
+
+/* Clear register struct.  */
+#define clear_struct_registers \
+  rax = rbx = rcx = rdx = rdi = rsi = rbp = rsp \
+    = r8 = r9 = r10 = r11 = r12 = r13 = r14 = r15 = 0; \
+  memset (&iregs, 0, sizeof (iregs)); \
+  memset (&fregs, 0, sizeof (fregs)); \
+  memset (zmm_regs, 0, sizeof (zmm_regs)); \
+  memset (x87_regs, 0, sizeof (x87_regs));
+
+/* Clear both hardware and register structs for integers.  */
+#define clear_int_registers \
+  clear_struct_registers \
+  clear_int_hardware_registers
+
+/* TODO: Do the checking.  */
+#define check_f_arguments(T) do { \
+  assert (num_fregs <= 0 || fregs.zmm0._ ## T [0] == zmm_regs[0]._ ## T [0]); \
+  assert (num_fregs <= 1 || fregs.zmm1._ ## T [0] == zmm_regs[1]._ ## T [0]); \
+  assert (num_fregs <= 2 || fregs.zmm2._ ## T [0] == zmm_regs[2]._ ## T [0]); \
+  assert (num_fregs <= 3 || fregs.zmm3._ ## T [0] == zmm_regs[3]._ ## T [0]); \
+  assert (num_fregs <= 4 || fregs.zmm4._ ## T [0] == zmm_regs[4]._ ## T [0]); \
+  assert (num_fregs <= 5 || fregs.zmm5._ ## T [0] == zmm_regs[5]._ ## T [0]); \
+  assert (num_fregs <= 6 || fregs.zmm6._ ## T [0] == zmm_regs[6]._ ## T [0]); \
+  assert (num_fregs <= 7 || fregs.zmm7._ ## T [0] == zmm_regs[7]._ ## T [0]); \
+  } while (0)
+
+#define check_float_arguments check_f_arguments(float)
+#define check_double_arguments check_f_arguments(double)
+
+#define check_vector_arguments(T,O) do { \
+  assert (num_fregs <= 0 \
+	  || memcmp (((char *) &fregs.zmm0) + (O), \
+		     &zmm_regs[0], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 1 \
+	  || memcmp (((char *) &fregs.zmm1) + (O), \
+		     &zmm_regs[1], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 2 \
+	  || memcmp (((char *) &fregs.zmm2) + (O), \
+		     &zmm_regs[2], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 3 \
+	  || memcmp (((char *) &fregs.zmm3) + (O), \
+		     &zmm_regs[3], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 4 \
+	  || memcmp (((char *) &fregs.zmm4) + (O), \
+		     &zmm_regs[4], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 5 \
+	  || memcmp (((char *) &fregs.zmm5) + (O), \
+		     &zmm_regs[5], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 6 \
+	  || memcmp (((char *) &fregs.zmm6) + (O), \
+		     &zmm_regs[6], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  assert (num_fregs <= 7 \
+	  || memcmp (((char *) &fregs.zmm7) + (O), \
+		     &zmm_regs[7], \
+		     sizeof (__ ## T) - (O)) == 0); \
+  } while (0)
+
+#define check_m64_arguments check_vector_arguments(m64, 0)
+#define check_m128_arguments check_vector_arguments(m128, 0)
+#define check_m256_arguments check_vector_arguments(m256, 0)
+#define check_m512_arguments check_vector_arguments(m512, 0)
+
+#endif /* INCLUDED_ARGS_H  */
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/asm-support.S b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/asm-support.S
new file mode 100644
index 00000000000..0ef82876dd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/asm-support.S
@@ -0,0 +1,97 @@ 
+	.text
+	.p2align 4,,15
+.globl snapshot
+	.type	snapshot, @function
+snapshot:
+.LFB3:
+	movq	%rax, rax(%rip)
+	movq	%rbx, rbx(%rip)
+	movq	%rcx, rcx(%rip)
+	movq	%rdx, rdx(%rip)
+	movq	%rdi, rdi(%rip)
+	movq	%rsi, rsi(%rip)
+	movq	%rbp, rbp(%rip)
+	movq	%rsp, rsp(%rip)
+	movq	%r8, r8(%rip)
+	movq	%r9, r9(%rip)
+	movq	%r10, r10(%rip)
+	movq	%r11, r11(%rip)
+	movq	%r12, r12(%rip)
+	movq	%r13, r13(%rip)
+	movq	%r14, r14(%rip)
+	movq	%r15, r15(%rip)
+	vmovdqu32 %zmm0, zmm_regs+0(%rip)
+	vmovdqu32 %zmm1, zmm_regs+64(%rip)
+	vmovdqu32 %zmm2, zmm_regs+128(%rip)
+	vmovdqu32 %zmm3, zmm_regs+192(%rip)
+	vmovdqu32 %zmm4, zmm_regs+256(%rip)
+	vmovdqu32 %zmm5, zmm_regs+320(%rip)
+	vmovdqu32 %zmm6, zmm_regs+384(%rip)
+	vmovdqu32 %zmm7, zmm_regs+448(%rip)
+	vmovdqu32 %zmm8, zmm_regs+512(%rip)
+	vmovdqu32 %zmm9, zmm_regs+576(%rip)
+	vmovdqu32 %zmm10, zmm_regs+640(%rip)
+	vmovdqu32 %zmm11, zmm_regs+704(%rip)
+	vmovdqu32 %zmm12, zmm_regs+768(%rip)
+	vmovdqu32 %zmm13, zmm_regs+832(%rip)
+	vmovdqu32 %zmm14, zmm_regs+896(%rip)
+	vmovdqu32 %zmm15, zmm_regs+960(%rip)
+	vmovdqu32 %zmm16, zmm_regs+1024(%rip)
+	vmovdqu32 %zmm17, zmm_regs+1088(%rip)
+	vmovdqu32 %zmm18, zmm_regs+1152(%rip)
+	vmovdqu32 %zmm19, zmm_regs+1216(%rip)
+	vmovdqu32 %zmm20, zmm_regs+1280(%rip)
+	vmovdqu32 %zmm21, zmm_regs+1344(%rip)
+	vmovdqu32 %zmm22, zmm_regs+1408(%rip)
+	vmovdqu32 %zmm23, zmm_regs+1472(%rip)
+	vmovdqu32 %zmm24, zmm_regs+1536(%rip)
+	vmovdqu32 %zmm25, zmm_regs+1600(%rip)
+	vmovdqu32 %zmm26, zmm_regs+1664(%rip)
+	vmovdqu32 %zmm27, zmm_regs+1728(%rip)
+	vmovdqu32 %zmm28, zmm_regs+1792(%rip)
+	vmovdqu32 %zmm29, zmm_regs+1856(%rip)
+	vmovdqu32 %zmm30, zmm_regs+1920(%rip)
+	vmovdqu32 %zmm31, zmm_regs+1984(%rip)
+	jmp	*callthis(%rip)
+.LFE3:
+	.size	snapshot, .-snapshot
+
+	.p2align 4,,15
+.globl snapshot_ret
+	.type	snapshot_ret, @function
+snapshot_ret:
+	movq	%rdi, rdi(%rip)
+	subq	$8, %rsp
+	call	*callthis(%rip)
+	addq	$8, %rsp
+	movq	%rax, rax(%rip)
+	movq	%rdx, rdx(%rip)
+	vmovdqu32	%zmm0, zmm_regs+0(%rip)
+	vmovdqu32	%zmm1, zmm_regs+64(%rip)
+	fstpt	x87_regs(%rip)
+	fstpt	x87_regs+16(%rip)
+	fldt	x87_regs+16(%rip)
+	fldt	x87_regs(%rip)
+	ret
+	.size	snapshot_ret, .-snapshot_ret
+
+	.comm	callthis,8,8
+	.comm	rax,8,8
+	.comm	rbx,8,8
+	.comm	rcx,8,8
+	.comm	rdx,8,8
+	.comm	rsi,8,8
+	.comm	rdi,8,8
+	.comm	rsp,8,8
+	.comm	rbp,8,8
+	.comm	r8,8,8
+	.comm	r9,8,8
+	.comm	r10,8,8
+	.comm	r11,8,8
+	.comm	r12,8,8
+	.comm	r13,8,8
+	.comm	r14,8,8
+	.comm	r15,8,8
+	.comm	zmm_regs,2048,64
+	.comm	x87_regs,128,32
+	.comm   volatile_var,8,8
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/avx512fp16-zmm-check.h b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/avx512fp16-zmm-check.h
new file mode 100644
index 00000000000..4b882cc11fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/avx512fp16-zmm-check.h
@@ -0,0 +1,4 @@ 
+#define AVX512VL(ebx) 1
+#define XSTATE_MASK (XSTATE_SSE | XSTATE_YMM | XSTATE_ZMM \
+		     | XSTATE_HI_ZMM | XSTATE_OPMASK)
+#include "../avx512fp16-check.h"
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_m512_returning.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_m512_returning.c
new file mode 100644
index 00000000000..5cb59436cfd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_m512_returning.c
@@ -0,0 +1,62 @@ 
+#include <stdio.h>
+#include "avx512fp16-zmm-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+__m512
+fun_test_returning___m512 (void)
+{
+  volatile_var++;
+  return (__m512){73,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+}
+
+__m512h
+fun_test_returning___m512h (void)
+{
+  volatile_var++;
+  return (__m512h){ 1.1f16, 2.2f16, 3.3f16, 4.4f16,
+                    5.5f16, 6.6f16, 7.7f16, 8.8f16,
+                    9.9f16,  10.10f16,   11.11f16, 12.12f16,
+                    13.13f16, 14.14f16,  15.15f16, 16.16f16,
+                    17.17f16, 18.18f16,  19.19f16, 20.20f16,
+                    21.21f16, 22.22f16,  23.23f16, 24.24f16,
+                    25.25f16, 26.26f16,  27.27f16, 28.28f16,
+                    29.29f16, 30.30f16,  31.31f16, 32.32f16};
+}
+
+__m512 test_512;
+__m512h test_512h;
+
+static void
+do_test (void)
+{
+  unsigned failed = 0;
+  ZMM_T zmmt1, zmmt2;
+
+  clear_struct_registers;
+  test_512 = (__m512){73,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  zmmt1._m512[0] = test_512;
+  zmmt2._m512[0] = WRAP_RET (fun_test_returning___m512)();
+  if (memcmp (&zmmt1, &zmmt2, sizeof (zmmt2)) != 0)
+    printf ("fail m512\n"), failed++;
+
+  clear_struct_registers;
+  test_512h = (__m512h){ 1.1f16, 2.2f16, 3.3f16, 4.4f16,
+                         5.5f16, 6.6f16, 7.7f16, 8.8f16,
+                         9.9f16,  10.10f16,   11.11f16, 12.12f16,
+                         13.13f16, 14.14f16,  15.15f16, 16.16f16,
+                         17.17f16, 18.18f16,  19.19f16, 20.20f16,
+                         21.21f16, 22.22f16,  23.23f16, 24.24f16,
+                         25.25f16, 26.26f16,  27.27f16, 28.28f16,
+                         29.29f16, 30.30f16,  31.31f16, 32.32f16};
+  zmmt1._m512h[0] = test_512h;
+  zmmt2._m512h[0] = WRAP_RET (fun_test_returning___m512h)();
+  if (memcmp (&zmmt1, &zmmt2, sizeof (zmmt2)) != 0)
+    printf ("fail m512h\n"), failed++;
+
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_m512.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_m512.c
new file mode 100644
index 00000000000..ad5ba2e7f92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_m512.c
@@ -0,0 +1,380 @@ 
+#include <stdio.h>
+#include "avx512fp16-zmm-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+/* This struct holds values for argument checking.  */
+struct
+{
+  ZMM_T i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15,
+    i16, i17, i18, i19, i20, i21, i22, i23;
+} 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)
+
+fun_check_passing_m512_8_values (__m512 i0 ATTRIBUTE_UNUSED,
+				 __m512 i1 ATTRIBUTE_UNUSED,
+				 __m512 i2 ATTRIBUTE_UNUSED,
+				 __m512 i3 ATTRIBUTE_UNUSED,
+				 __m512 i4 ATTRIBUTE_UNUSED,
+				 __m512 i5 ATTRIBUTE_UNUSED,
+				 __m512 i6 ATTRIBUTE_UNUSED,
+				 __m512 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m512);
+  compare (values.i1, i1, __m512);
+  compare (values.i2, i2, __m512);
+  compare (values.i3, i3, __m512);
+  compare (values.i4, i4, __m512);
+  compare (values.i5, i5, __m512);
+  compare (values.i6, i6, __m512);
+  compare (values.i7, i7, __m512);
+}
+
+fun_check_passing_m512h_8_values (__m512h i0 ATTRIBUTE_UNUSED,
+				  __m512h i1 ATTRIBUTE_UNUSED,
+				  __m512h i2 ATTRIBUTE_UNUSED,
+				  __m512h i3 ATTRIBUTE_UNUSED,
+				  __m512h i4 ATTRIBUTE_UNUSED,
+				  __m512h i5 ATTRIBUTE_UNUSED,
+				  __m512h i6 ATTRIBUTE_UNUSED,
+				  __m512h i7 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m512h);
+  compare (values.i1, i1, __m512h);
+  compare (values.i2, i2, __m512h);
+  compare (values.i3, i3, __m512h);
+  compare (values.i4, i4, __m512h);
+  compare (values.i5, i5, __m512h);
+  compare (values.i6, i6, __m512h);
+  compare (values.i7, i7, __m512h);
+}
+
+void
+fun_check_passing_m512_8_regs (__m512 i0 ATTRIBUTE_UNUSED,
+			       __m512 i1 ATTRIBUTE_UNUSED,
+			       __m512 i2 ATTRIBUTE_UNUSED,
+			       __m512 i3 ATTRIBUTE_UNUSED,
+			       __m512 i4 ATTRIBUTE_UNUSED,
+			       __m512 i5 ATTRIBUTE_UNUSED,
+			       __m512 i6 ATTRIBUTE_UNUSED,
+			       __m512 i7 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+fun_check_passing_m512h_8_regs (__m512h i0 ATTRIBUTE_UNUSED,
+				__m512h i1 ATTRIBUTE_UNUSED,
+				__m512h i2 ATTRIBUTE_UNUSED,
+				__m512h i3 ATTRIBUTE_UNUSED,
+				__m512h i4 ATTRIBUTE_UNUSED,
+				__m512h i5 ATTRIBUTE_UNUSED,
+				__m512h i6 ATTRIBUTE_UNUSED,
+				__m512h i7 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+fun_check_passing_m512_20_values (__m512 i0 ATTRIBUTE_UNUSED,
+				  __m512 i1 ATTRIBUTE_UNUSED,
+				  __m512 i2 ATTRIBUTE_UNUSED,
+				  __m512 i3 ATTRIBUTE_UNUSED,
+				  __m512 i4 ATTRIBUTE_UNUSED,
+				  __m512 i5 ATTRIBUTE_UNUSED,
+				  __m512 i6 ATTRIBUTE_UNUSED,
+				  __m512 i7 ATTRIBUTE_UNUSED,
+				  __m512 i8 ATTRIBUTE_UNUSED,
+				  __m512 i9 ATTRIBUTE_UNUSED,
+				  __m512 i10 ATTRIBUTE_UNUSED,
+				  __m512 i11 ATTRIBUTE_UNUSED,
+				  __m512 i12 ATTRIBUTE_UNUSED,
+				  __m512 i13 ATTRIBUTE_UNUSED,
+				  __m512 i14 ATTRIBUTE_UNUSED,
+				  __m512 i15 ATTRIBUTE_UNUSED,
+				  __m512 i16 ATTRIBUTE_UNUSED,
+				  __m512 i17 ATTRIBUTE_UNUSED,
+				  __m512 i18 ATTRIBUTE_UNUSED,
+				  __m512 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m512);
+  compare (values.i1, i1, __m512);
+  compare (values.i2, i2, __m512);
+  compare (values.i3, i3, __m512);
+  compare (values.i4, i4, __m512);
+  compare (values.i5, i5, __m512);
+  compare (values.i6, i6, __m512);
+  compare (values.i7, i7, __m512);
+  compare (values.i8, i8, __m512);
+  compare (values.i9, i9, __m512);
+  compare (values.i10, i10, __m512);
+  compare (values.i11, i11, __m512);
+  compare (values.i12, i12, __m512);
+  compare (values.i13, i13, __m512);
+  compare (values.i14, i14, __m512);
+  compare (values.i15, i15, __m512);
+  compare (values.i16, i16, __m512);
+  compare (values.i17, i17, __m512);
+  compare (values.i18, i18, __m512);
+  compare (values.i19, i19, __m512);
+}
+
+void
+fun_check_passing_m512h_20_values (__m512h i0 ATTRIBUTE_UNUSED,
+				   __m512h i1 ATTRIBUTE_UNUSED,
+				   __m512h i2 ATTRIBUTE_UNUSED,
+				   __m512h i3 ATTRIBUTE_UNUSED,
+				   __m512h i4 ATTRIBUTE_UNUSED,
+				   __m512h i5 ATTRIBUTE_UNUSED,
+				   __m512h i6 ATTRIBUTE_UNUSED,
+				   __m512h i7 ATTRIBUTE_UNUSED,
+				   __m512h i8 ATTRIBUTE_UNUSED,
+				   __m512h i9 ATTRIBUTE_UNUSED,
+				   __m512h i10 ATTRIBUTE_UNUSED,
+				   __m512h i11 ATTRIBUTE_UNUSED,
+				   __m512h i12 ATTRIBUTE_UNUSED,
+				   __m512h i13 ATTRIBUTE_UNUSED,
+				   __m512h i14 ATTRIBUTE_UNUSED,
+				   __m512h i15 ATTRIBUTE_UNUSED,
+				   __m512h i16 ATTRIBUTE_UNUSED,
+				   __m512h i17 ATTRIBUTE_UNUSED,
+				   __m512h i18 ATTRIBUTE_UNUSED,
+				   __m512h i19 ATTRIBUTE_UNUSED)
+{
+  /* Check argument values.  */
+  compare (values.i0, i0, __m512h);
+  compare (values.i1, i1, __m512h);
+  compare (values.i2, i2, __m512h);
+  compare (values.i3, i3, __m512h);
+  compare (values.i4, i4, __m512h);
+  compare (values.i5, i5, __m512h);
+  compare (values.i6, i6, __m512h);
+  compare (values.i7, i7, __m512h);
+  compare (values.i8, i8, __m512h);
+  compare (values.i9, i9, __m512h);
+  compare (values.i10, i10, __m512h);
+  compare (values.i11, i11, __m512h);
+  compare (values.i12, i12, __m512h);
+  compare (values.i13, i13, __m512h);
+  compare (values.i14, i14, __m512h);
+  compare (values.i15, i15, __m512h);
+  compare (values.i16, i16, __m512h);
+  compare (values.i17, i17, __m512h);
+  compare (values.i18, i18, __m512h);
+  compare (values.i19, i19, __m512h);
+}
+
+void
+fun_check_passing_m512_20_regs (__m512 i0 ATTRIBUTE_UNUSED,
+				__m512 i1 ATTRIBUTE_UNUSED,
+				__m512 i2 ATTRIBUTE_UNUSED,
+				__m512 i3 ATTRIBUTE_UNUSED,
+				__m512 i4 ATTRIBUTE_UNUSED,
+				__m512 i5 ATTRIBUTE_UNUSED,
+				__m512 i6 ATTRIBUTE_UNUSED,
+				__m512 i7 ATTRIBUTE_UNUSED,
+				__m512 i8 ATTRIBUTE_UNUSED,
+				__m512 i9 ATTRIBUTE_UNUSED,
+				__m512 i10 ATTRIBUTE_UNUSED,
+				__m512 i11 ATTRIBUTE_UNUSED,
+				__m512 i12 ATTRIBUTE_UNUSED,
+				__m512 i13 ATTRIBUTE_UNUSED,
+				__m512 i14 ATTRIBUTE_UNUSED,
+				__m512 i15 ATTRIBUTE_UNUSED,
+				__m512 i16 ATTRIBUTE_UNUSED,
+				__m512 i17 ATTRIBUTE_UNUSED,
+				__m512 i18 ATTRIBUTE_UNUSED,
+				__m512 i19 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+fun_check_passing_m512h_20_regs (__m512h i0 ATTRIBUTE_UNUSED,
+				 __m512h i1 ATTRIBUTE_UNUSED,
+				 __m512h i2 ATTRIBUTE_UNUSED,
+				 __m512h i3 ATTRIBUTE_UNUSED,
+				 __m512h i4 ATTRIBUTE_UNUSED,
+				 __m512h i5 ATTRIBUTE_UNUSED,
+				 __m512h i6 ATTRIBUTE_UNUSED,
+				 __m512h i7 ATTRIBUTE_UNUSED,
+				 __m512h i8 ATTRIBUTE_UNUSED,
+				 __m512h i9 ATTRIBUTE_UNUSED,
+				 __m512h i10 ATTRIBUTE_UNUSED,
+				 __m512h i11 ATTRIBUTE_UNUSED,
+				 __m512h i12 ATTRIBUTE_UNUSED,
+				 __m512h i13 ATTRIBUTE_UNUSED,
+				 __m512h i14 ATTRIBUTE_UNUSED,
+				 __m512h i15 ATTRIBUTE_UNUSED,
+				 __m512h i16 ATTRIBUTE_UNUSED,
+				 __m512h i17 ATTRIBUTE_UNUSED,
+				 __m512h i18 ATTRIBUTE_UNUSED,
+				 __m512h i19 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+#define def_check_passing8(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _func1, _func2, 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; \
+  WRAP_CALL(_func1) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7); \
+  \
+  clear_struct_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; \
+  num_fregs = 8; \
+  WRAP_CALL(_func2) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7);
+
+#define def_check_passing20(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, \
+			    _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, \
+			    _i18, _i19, _func1, _func2, 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; \
+  values.i10.TYPE[0] = _i10; \
+  values.i11.TYPE[0] = _i11; \
+  values.i12.TYPE[0] = _i12; \
+  values.i13.TYPE[0] = _i13; \
+  values.i14.TYPE[0] = _i14; \
+  values.i15.TYPE[0] = _i15; \
+  values.i16.TYPE[0] = _i16; \
+  values.i17.TYPE[0] = _i17; \
+  values.i18.TYPE[0] = _i18; \
+  values.i19.TYPE[0] = _i19; \
+  WRAP_CALL(_func1) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, \
+		     _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, \
+		     _i18, _i19); \
+  \
+  clear_struct_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; \
+  num_fregs = 8; \
+  WRAP_CALL(_func2) (_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, \
+		     _i10, _i11, _i12, _i13, _i14, _i15, _i16, _i17, \
+		     _i18, _i19);
+
+void
+test_m512_on_stack ()
+{
+  __m512 x[8];
+  int i;
+  for (i = 0; i < 8; i++)
+    x[i] = (__m512){32 + i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m512-8";
+  def_check_passing8 (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
+		      fun_check_passing_m512_8_values,
+		      fun_check_passing_m512_8_regs, _m512);
+}
+
+void
+test_m512h_on_stack ()
+{
+  __m512h x[8];
+  int i;
+  for (i = 0; i < 8; i++)
+    x[i] = (__m512h){1.1f16 + i, 2.2f16 + i, 3.3f16 + i, 4.4f16 + i,
+		     5.5f16 + i, 6.6f16 + i, 7.7f16 + i, 8.8f16 + i,
+		     9.9f16 + i, 10.10f16 + i, 11.11f16 + i, 12.12f16 + i,
+		     13.13f16 + i, 14.14f16 + i, 15.15f16 + i, 16.16f16 + i,
+		     17.17f16 + i, 18.18f16 + i, 19.19f16 + i, 20.20f16 + i,
+		     21.21f16 + i, 22.22f16 + i, 23.23f16 + i, 24.24f16 + i,
+		     25.25f16 + i, 26.26f16 + i, 27.27f16 + i, 28.28f16 + i,
+		     29.29f16 + i, 30.30f16 + i, 31.31f16 + i, 32.32f16 + i};
+
+  pass = "m512h-8";
+  def_check_passing8 (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
+		      fun_check_passing_m512h_8_values,
+		      fun_check_passing_m512h_8_regs, _m512h);
+}
+
+void
+test_too_many_m512 ()
+{
+  __m512 x[20];
+  int i;
+  for (i = 0; i < 20; i++)
+    x[i] = (__m512){32 + i, 0, 0, 0, 0, 0, 0, 0};
+  pass = "m512-20";
+  def_check_passing20 (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8],
+		       x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16],
+		       x[17], x[18], x[19], fun_check_passing_m512_20_values,
+		       fun_check_passing_m512_20_regs, _m512);
+}
+
+void
+test_too_many_m512h ()
+{
+  __m512h x[20];
+  int i;
+  for (i = 0; i < 20; i++)
+    x[i] = (__m512h){ 1.1f16 + i, 2.2f16 + i, 3.3f16 + i, 4.4f16 + i,
+		      5.5f16 + i, 6.6f16 + i, 7.7f16 + i, 8.8f16 + i,
+		      9.9f16 + i, 10.10f16 + i, 11.11f16 + i, 12.12f16 + i,
+		      13.13f16 + i, 14.14f16 + i, 15.15f16 + i, 16.16f16 + i,
+		      17.17f16 + i, 18.18f16 + i, 19.19f16 + i, 20.20f16 + i,
+		      21.21f16 + i, 22.22f16 + i, 23.23f16 + i, 24.24f16 + i,
+		      25.25f16 + i, 26.26f16 + i, 27.27f16 + i, 28.28f16 + i,
+		      29.29f16 + i, 30.30f16 + i, 31.31f16 + i, 32.32f16 + i};
+  pass = "m512h-20";
+  def_check_passing20 (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8],
+		       x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16],
+		       x[17], x[18], x[19], fun_check_passing_m512h_20_values,
+		       fun_check_passing_m512h_20_regs, _m512h);
+}
+
+static void
+do_test (void)
+{
+  test_m512_on_stack ();
+  test_too_many_m512 ();
+  test_m512h_on_stack ();
+  test_too_many_m512h ();
+  if (failed)
+    abort ();
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_structs.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_structs.c
new file mode 100644
index 00000000000..734e0f8e9e9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_structs.c
@@ -0,0 +1,123 @@ 
+#include "avx512fp16-zmm-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+struct m512_struct
+{
+  __m512 x;
+};
+
+struct m512h_struct
+{
+  __m512h x;
+};
+
+struct m512_2_struct
+{
+  __m512 x1, x2;
+};
+
+struct m512h_2_struct
+{
+  __m512h x1, x2;
+};
+
+/* Check that the struct is passed as the individual members in fregs.  */
+void
+check_struct_passing1 (struct m512_struct ms1 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms2 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms3 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms4 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms5 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms6 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms7 ATTRIBUTE_UNUSED,
+		       struct m512_struct ms8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_struct_passing1h (struct m512h_struct ms1 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms2 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms3 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms4 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms5 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms6 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms7 ATTRIBUTE_UNUSED,
+			struct m512h_struct ms8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_struct_passing2 (struct m512_2_struct ms ATTRIBUTE_UNUSED)
+{
+  /* Check the passing on the stack by comparing the address of the
+     stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&ms.x1 == rsp+8);
+  assert ((unsigned long)&ms.x2 == rsp+72);
+}
+
+void
+check_struct_passing2h (struct m512h_2_struct ms ATTRIBUTE_UNUSED)
+{
+  /* Check the passing on the stack by comparing the address of the
+     stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&ms.x1 == rsp+8);
+  assert ((unsigned long)&ms.x2 == rsp+72);
+}
+
+static void
+do_test (void)
+{
+  struct m512_struct m512s [8];
+  struct m512h_struct m512hs [8];
+  struct m512_2_struct m512_2s = {
+      { 48.394, 39.3, -397.9, 3484.9, -8.394, -93.3, 7.9, 84.94,
+	48.3941, 39.31, -397.91, 3484.91, -8.3941, -93.31, 7.91, 84.941 },
+      { -8.394, -3.3, -39.9, 34.9, 7.9, 84.94, -48.394, 39.3,
+	-8.3942, -3.32, -39.92, 34.92, 7.92, 84.942, -48.3942, 39.32 }
+  };
+  struct m512h_2_struct m512h_2s = {
+      { 58.395f16, 39.3f16, -397.9f16, 3585.9f16, -8.395f16, -93.3f16, 7.9f16, 85.95f16,
+        58.395f16, 39.3f16, -397.9f16, 3585.9f16, -8.395f16, -93.3f16, 7.9f16, 85.95f16,
+        58.395f16, 39.3f16, -397.9f16, 3585.9f16, -8.395f16, -93.3f16, 7.9f16, 85.95f16,
+	58.3951f16, 39.31f16, -397.91f16, 3585.91f16, -8.3951f16, -93.31f16, 7.91f16, 85.951f16},
+      { 67.396f16, 39.3f16, -397.9f16, 3676.9f16, -7.396f16, -93.3f16, 7.9f16, 76.96f16,
+        67.396f16, 39.3f16, -397.9f16, 3676.9f16, -7.396f16, -93.3f16, 7.9f16, 76.96f16,
+        67.396f16, 39.3f16, -397.9f16, 3676.9f16, -7.396f16, -93.3f16, 7.9f16, 76.96f16,
+	67.3961f16, 39.31f16, -397.91f16, 3676.91f16, -7.3961f16, -93.31f16, 7.91f16, 76.961f16},
+  };
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      m512s[i].x = (__m512){32+i, 0, i, 0, -i, 0, i - 12, i + 8,
+			    32+i, 0, i, 0, -i, 0, i - 12, i + 8};
+      m512hs[i].x = (__m512h){33+i, 1, i, 2, -i, 0, i - 15, i + 9,
+			      34+i, 1, i, 2, -i, 0, i - 15, i + 9,
+			      35+i, 1, i, 2, -i, 0, i - 15, i + 9,
+			      36+i, 1, i, 2, -i, 0, i - 15, i + 9};
+    }
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    (&fregs.zmm0)[i]._m512[0] = m512s[i].x;
+  num_fregs = 8;
+  WRAP_CALL (check_struct_passing1)(m512s[0], m512s[1], m512s[2], m512s[3],
+				    m512s[4], m512s[5], m512s[6], m512s[7]);
+  WRAP_CALL (check_struct_passing2)(m512_2s);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    (&fregs.zmm0)[i]._m512h[0] = m512hs[i].x;
+  num_fregs = 8;
+  WRAP_CALL (check_struct_passing1h)(m512hs[0], m512hs[1], m512hs[2], m512hs[3],
+				    m512hs[4], m512hs[5], m512hs[6], m512hs[7]);
+  WRAP_CALL (check_struct_passing2h)(m512h_2s);
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_unions.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_unions.c
new file mode 100644
index 00000000000..fa801fbf7ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_passing_unions.c
@@ -0,0 +1,415 @@ 
+#include "avx512fp16-zmm-check.h"
+#include "args.h"
+
+struct IntegerRegisters iregs;
+struct FloatRegisters fregs;
+unsigned int num_iregs, num_fregs;
+
+union un1
+{
+  __m512 x;
+  float f;
+};
+
+union un2
+{
+  __m512 x;
+  double d;
+};
+
+union un3
+{
+  __m512 x;
+  __m128 v;
+};
+
+union un4
+{
+  __m512 x;
+  long double ld;
+};
+
+union un5
+{
+  __m512 x;
+  int i;
+};
+
+union un6
+{
+  __m512 x;
+  __m256 v;
+};
+
+union un1h
+{
+  __m512 x;
+  _Float16 f;
+};
+
+union un1hf
+{
+  __m512h x;
+  float f;
+};
+
+union un1hh
+{
+  __m512h x;
+  _Float16 f;
+};
+
+union un2h
+{
+  __m512h x;
+  double d;
+};
+
+union un3h
+{
+  __m512h x;
+  __m128 v;
+};
+
+union un4h
+{
+  __m512h x;
+  long double ld;
+};
+
+union un5h
+{
+  __m512h x;
+  int i;
+};
+
+union un6h
+{
+  __m512h x;
+  __m256 v;
+};
+
+void
+check_union_passing1(union un1 u1 ATTRIBUTE_UNUSED,
+		     union un1 u2 ATTRIBUTE_UNUSED,
+		     union un1 u3 ATTRIBUTE_UNUSED,
+		     union un1 u4 ATTRIBUTE_UNUSED,
+		     union un1 u5 ATTRIBUTE_UNUSED,
+		     union un1 u6 ATTRIBUTE_UNUSED,
+		     union un1 u7 ATTRIBUTE_UNUSED,
+		     union un1 u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing1h(union un1h u1 ATTRIBUTE_UNUSED,
+		      union un1h u2 ATTRIBUTE_UNUSED,
+		      union un1h u3 ATTRIBUTE_UNUSED,
+		      union un1h u4 ATTRIBUTE_UNUSED,
+		      union un1h u5 ATTRIBUTE_UNUSED,
+		      union un1h u6 ATTRIBUTE_UNUSED,
+		      union un1h u7 ATTRIBUTE_UNUSED,
+		      union un1h u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing1hf(union un1hf u1 ATTRIBUTE_UNUSED,
+		       union un1hf u2 ATTRIBUTE_UNUSED,
+		       union un1hf u3 ATTRIBUTE_UNUSED,
+		       union un1hf u4 ATTRIBUTE_UNUSED,
+		       union un1hf u5 ATTRIBUTE_UNUSED,
+		       union un1hf u6 ATTRIBUTE_UNUSED,
+		       union un1hf u7 ATTRIBUTE_UNUSED,
+		       union un1hf u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing1hh(union un1hh u1 ATTRIBUTE_UNUSED,
+		       union un1hh u2 ATTRIBUTE_UNUSED,
+		       union un1hh u3 ATTRIBUTE_UNUSED,
+		       union un1hh u4 ATTRIBUTE_UNUSED,
+		       union un1hh u5 ATTRIBUTE_UNUSED,
+		       union un1hh u6 ATTRIBUTE_UNUSED,
+		       union un1hh u7 ATTRIBUTE_UNUSED,
+		       union un1hh u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+
+void
+check_union_passing2(union un2 u1 ATTRIBUTE_UNUSED,
+		     union un2 u2 ATTRIBUTE_UNUSED,
+		     union un2 u3 ATTRIBUTE_UNUSED,
+		     union un2 u4 ATTRIBUTE_UNUSED,
+		     union un2 u5 ATTRIBUTE_UNUSED,
+		     union un2 u6 ATTRIBUTE_UNUSED,
+		     union un2 u7 ATTRIBUTE_UNUSED,
+		     union un2 u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing2h(union un2h u1 ATTRIBUTE_UNUSED,
+		      union un2h u2 ATTRIBUTE_UNUSED,
+		      union un2h u3 ATTRIBUTE_UNUSED,
+		      union un2h u4 ATTRIBUTE_UNUSED,
+		      union un2h u5 ATTRIBUTE_UNUSED,
+		      union un2h u6 ATTRIBUTE_UNUSED,
+		      union un2h u7 ATTRIBUTE_UNUSED,
+		      union un2h u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing3(union un3 u1 ATTRIBUTE_UNUSED,
+		     union un3 u2 ATTRIBUTE_UNUSED,
+		     union un3 u3 ATTRIBUTE_UNUSED,
+		     union un3 u4 ATTRIBUTE_UNUSED,
+		     union un3 u5 ATTRIBUTE_UNUSED,
+		     union un3 u6 ATTRIBUTE_UNUSED,
+		     union un3 u7 ATTRIBUTE_UNUSED,
+		     union un3 u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing3h(union un3h u1 ATTRIBUTE_UNUSED,
+		      union un3h u2 ATTRIBUTE_UNUSED,
+		      union un3h u3 ATTRIBUTE_UNUSED,
+		      union un3h u4 ATTRIBUTE_UNUSED,
+		      union un3h u5 ATTRIBUTE_UNUSED,
+		      union un3h u6 ATTRIBUTE_UNUSED,
+		      union un3h u7 ATTRIBUTE_UNUSED,
+		      union un3h u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing4(union un4 u ATTRIBUTE_UNUSED)
+{
+   /* Check the passing on the stack by comparing the address of the
+      stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&u.x == rsp+8);
+  assert ((unsigned long)&u.ld == rsp+8);
+}
+
+void
+check_union_passing4h(union un4h u ATTRIBUTE_UNUSED)
+{
+   /* Check the passing on the stack by comparing the address of the
+      stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&u.x == rsp+8);
+  assert ((unsigned long)&u.ld == rsp+8);
+}
+
+void
+check_union_passing5(union un5 u ATTRIBUTE_UNUSED)
+{
+   /* Check the passing on the stack by comparing the address of the
+      stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&u.x == rsp+8);
+  assert ((unsigned long)&u.i == rsp+8);
+}
+
+void
+check_union_passing5h(union un5h u ATTRIBUTE_UNUSED)
+{
+   /* Check the passing on the stack by comparing the address of the
+      stack elements to the expected place on the stack.  */
+  assert ((unsigned long)&u.x == rsp+8);
+  assert ((unsigned long)&u.i == rsp+8);
+}
+
+void
+check_union_passing6(union un6 u1 ATTRIBUTE_UNUSED,
+		     union un6 u2 ATTRIBUTE_UNUSED,
+		     union un6 u3 ATTRIBUTE_UNUSED,
+		     union un6 u4 ATTRIBUTE_UNUSED,
+		     union un6 u5 ATTRIBUTE_UNUSED,
+		     union un6 u6 ATTRIBUTE_UNUSED,
+		     union un6 u7 ATTRIBUTE_UNUSED,
+		     union un6 u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+void
+check_union_passing6h(union un6h u1 ATTRIBUTE_UNUSED,
+		      union un6h u2 ATTRIBUTE_UNUSED,
+		      union un6h u3 ATTRIBUTE_UNUSED,
+		      union un6h u4 ATTRIBUTE_UNUSED,
+		      union un6h u5 ATTRIBUTE_UNUSED,
+		      union un6h u6 ATTRIBUTE_UNUSED,
+		      union un6h u7 ATTRIBUTE_UNUSED,
+		      union un6h u8 ATTRIBUTE_UNUSED)
+{
+  /* Check register contents.  */
+  check_m512_arguments;
+}
+
+#define check_union_passing1 WRAP_CALL(check_union_passing1)
+#define check_union_passing2 WRAP_CALL(check_union_passing2)
+#define check_union_passing3 WRAP_CALL(check_union_passing3)
+#define check_union_passing4 WRAP_CALL(check_union_passing4)
+#define check_union_passing5 WRAP_CALL(check_union_passing5)
+#define check_union_passing6 WRAP_CALL(check_union_passing6)
+
+#define check_union_passing1h WRAP_CALL(check_union_passing1h)
+#define check_union_passing1hf WRAP_CALL(check_union_passing1hf)
+#define check_union_passing1hh WRAP_CALL(check_union_passing1hh)
+#define check_union_passing2h WRAP_CALL(check_union_passing2h)
+#define check_union_passing3h WRAP_CALL(check_union_passing3h)
+#define check_union_passing4h WRAP_CALL(check_union_passing4h)
+#define check_union_passing5h WRAP_CALL(check_union_passing5h)
+#define check_union_passing6h WRAP_CALL(check_union_passing6h)
+
+
+static void
+do_test (void)
+{
+  union un1 u1[8];
+  union un2 u2[8];
+  union un3 u3[8];
+  union un4 u4;
+  union un5 u5;
+  union un6 u6[8];
+  union un1h u1h[8];
+  union un1hf u1hf[8];
+  union un1hh u1hh[8];
+  union un2h u2h[8];
+  union un3h u3h[8];
+  union un4h u4h;
+  union un5h u5h;
+  union un6h u6h[8];
+   int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      u1[i].x = (__m512){32+i, 0, i, 0, -i, 0, i - 12, i + 8,
+	                 32+i, 0, i, 0, -i, 0, i - 12, i + 8};
+
+      u1hf[i].x =  (__m512h){ 33+i, 1, i, 2, -i, 0, i - 15, i + 9,
+                              34+i, 1, i, 2, -i, 0, i - 15, i + 9,
+                              35+i, 1, i, 2, -i, 0, i - 15, i + 9,
+                              36+i, 1, i, 2, -i, 0, i - 15, i + 9};
+    }
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    (&fregs.zmm0)[i]._m512[0] = u1[i].x;
+  num_fregs = 8;
+  check_union_passing1(u1[0], u1[1], u1[2], u1[3],
+		       u1[4], u1[5], u1[6], u1[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u1h[i].x = u1[i].x;
+      (&fregs.zmm0)[i]._m512[0] = u1h[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing1h(u1h[0], u1h[1], u1h[2], u1h[3],
+		        u1h[4], u1h[5], u1h[6], u1h[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    (&fregs.zmm0)[i]._m512h[0] = u1hf[i].x;
+  num_fregs = 8;
+  check_union_passing1hf(u1hf[0], u1hf[1], u1hf[2], u1hf[3],
+		         u1hf[4], u1hf[5], u1hf[6], u1hf[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u1hh[i].x = u1hf[i].x;
+      (&fregs.zmm0)[i]._m512h[0] = u1hh[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing1hh(u1hh[0], u1hh[1], u1hh[2], u1hh[3],
+		         u1hh[4], u1hh[5], u1hh[6], u1hh[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u2[i].x = u1[i].x;
+      (&fregs.zmm0)[i]._m512[0] = u2[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing2(u2[0], u2[1], u2[2], u2[3],
+		       u2[4], u2[5], u2[6], u2[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u2h[i].x = u1hf[i].x;
+      (&fregs.zmm0)[i]._m512h[0] = u2h[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing2h(u2h[0], u2h[1], u2h[2], u2h[3],
+		        u2h[4], u2h[5], u2h[6], u2h[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u3[i].x = u1[i].x;
+      (&fregs.zmm0)[i]._m512[0] = u3[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing3(u3[0], u3[1], u3[2], u3[3],
+		       u3[4], u3[5], u3[6], u3[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u3h[i].x = u1hf[i].x;
+      (&fregs.zmm0)[i]._m512h[0] = u3h[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing3h(u3h[0], u3h[1], u3h[2], u3h[3],
+		        u3h[4], u3h[5], u3h[6], u3h[7]);
+
+  check_union_passing4(u4);
+  check_union_passing5(u5);
+
+  check_union_passing4h(u4h);
+  check_union_passing5h(u5h);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u6[i].x = u1[i].x;
+      (&fregs.zmm0)[i]._m512[0] = u6[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing6(u6[0], u6[1], u6[2], u6[3],
+		       u6[4], u6[5], u6[6], u6[7]);
+
+  clear_struct_registers;
+  for (i = 0; i < 8; i++)
+    {
+      u6h[i].x = u1hf[i].x;
+      (&fregs.zmm0)[i]._m512h[0] = u6h[i].x;
+    }
+  num_fregs = 8;
+  check_union_passing6h(u6h[0], u6h[1], u6h[2], u6h[3],
+		        u6h[4], u6h[5], u6h[6], u6h[7]);
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_varargs-m512.c b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_varargs-m512.c
new file mode 100644
index 00000000000..e6d165a8247
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/avx512fp16/m512h/test_varargs-m512.c
@@ -0,0 +1,164 @@ 
+/* Test variable number of 512-bit vector arguments passed to functions.  */
+
+#include <stdio.h>
+#include "avx512fp16-zmm-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);
+}
+
+void
+fun_check_passing_m512h_varargs (__m512h i0, __m512h i1, __m512h i2,
+				 __m512h i3, ...)
+{
+  /* Check argument values.  */
+  void **fp = __builtin_frame_address (0);
+  void *ra = __builtin_return_address (0);
+  __m512h *argp;
+
+  compare (values.i0, i0, __m512h);
+  compare (values.i1, i1, __m512h);
+  compare (values.i2, i2, __m512h);
+  compare (values.i3, i3, __m512h);
+
+  /* Get the pointer to the return address on stack.  */
+  while (*fp != ra)
+    fp++;
+
+  /* Skip the return address stack slot.  */
+  argp = (__m512h *)(((char *) fp) + 8);
+
+  /* Check __m512h arguments passed on stack.  */
+  compare (values.i4, argp[0], __m512h);
+  compare (values.i5, argp[1], __m512h);
+  compare (values.i6, argp[2], __m512h);
+  compare (values.i7, argp[3], __m512h);
+  compare (values.i8, argp[4], __m512h);
+  compare (values.i9, argp[5], __m512h);
+
+  /* Check register contents.  */
+  compare (fregs.zmm0, zmm_regs[0], __m512h);
+  compare (fregs.zmm1, zmm_regs[1], __m512h);
+  compare (fregs.zmm2, zmm_regs[2], __m512h);
+  compare (fregs.zmm3, zmm_regs[3], __m512h);
+}
+
+#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
+test_m512h_varargs (void)
+{
+  __m512h x[10];
+  int i;
+  for (i = 0; i < 10; i++)
+    x[i] = (__m512h) {
+        1.1f16 + i, 2.2f16 + i, 3.3f16 + i, 4.4f16 + i,
+	5.5f16 + i, 6.6f16 + i, 7.7f16 + i, 8.8f16 + i,
+	9.9f16 + i, 10.10f16 + i, 11.11f16 + i, 12.12f16 + i,
+	13.13f16 + i, 14.14f16 + i, 15.15f16 + i, 16.16f16 + i,
+	17.17f16 + i, 18.18f16 + i, 19.19f16 + i, 20.20f16 + i,
+	21.21f16 + i, 22.22f16 + i, 23.23f16 + i, 24.24f16 + i,
+	25.25f16 + i, 26.26f16 + i, 27.27f16 + i, 28.28f16 + i,
+	29.29f16 + i, 30.30f16 + i, 31.31f16 + i, 32.32f16 + i
+    };
+  pass = "m512h-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_m512h_varargs,
+				 _m512h);
+}
+
+void
+do_test (void)
+{
+  test_m512_varargs ();
+  test_m512h_varargs ();
+  if (failed)
+    abort ();
+}