diff mbox series

[pushed,v2,2/5] aarch64: Add svcount_t

Message ID 20231205102503.1923331-3-richard.sandiford@arm.com
State New
Headers show
Series aarch64: Add support for SME2 | expand

Commit Message

Richard Sandiford Dec. 5, 2023, 10:25 a.m. UTC
Some SME2 instructions interpret predicates as counters, rather than
as bit-per-byte masks.  The SME2 ACLE defines an svcount_t type for
this interpretation.

I don't think we have a better way of representing counters than
the VNx16BI that we use for masks.  The patch therefore doesn't
add a new mode for this representation.  It's just something that
is interpreted in context, a bit like signed vs. unsigned integers.

gcc/
	* config/aarch64/aarch64-sve-builtins-base.cc
	(svreinterpret_impl::fold): Handle reinterprets between svbool_t
	and svcount_t.
	(svreinterpret_impl::expand): Likewise.
	* config/aarch64/aarch64-sve-builtins-base.def (svreinterpret): Add
	b<->c forms.
	* config/aarch64/aarch64-sve-builtins.cc (TYPES_reinterpret_b): New
	type suffix list.
	(wrap_type_in_struct, register_type_decl): New functions, split out
	from...
	(register_tuple_type): ...here.
	(register_builtin_types): Handle svcount_t.
	(handle_arm_sve_h): Don't create tuples of svcount_t.
	* config/aarch64/aarch64-sve-builtins.def (svcount_t): New type.
	(c): New type suffix.
	* config/aarch64/aarch64-sve-builtins.h (TYPE_count): New type class.

gcc/testsuite/
	* g++.target/aarch64/sve/acle/general-c++/mangle_1.C: Add test
	for svcount_t.
	* g++.target/aarch64/sve/acle/general-c++/mangle_2.C: Likewise.
	* g++.target/aarch64/sve/acle/general-c++/svcount_1.C: New test.
	* gcc.target/aarch64/sve/acle/asm/test_sve_acle.h (TEST_DUAL_P)
	(TEST_DUAL_P_REV): New macros.
	* gcc.target/aarch64/sve/acle/asm/reinterpret_b.c: New test.
	* gcc.target/aarch64/sve/acle/general-c/load_1.c: Test passing
	an svcount_t.
	* gcc.target/aarch64/sve/acle/general-c/svcount_1.c: New test.
	* gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c: Test
	reinterprets involving svcount_t.
	* gcc.target/aarch64/sve/acle/general/attributes_7.c: Test svcount_t.
	* gcc.target/aarch64/sve/pcs/annotate_1.c: Likewise.
	* gcc.target/aarch64/sve/pcs/annotate_2.c: Likewise.
	* gcc.target/aarch64/sve/pcs/args_12.c: New test.
---
 .../aarch64/aarch64-sve-builtins-base.cc      |   8 +-
 .../aarch64/aarch64-sve-builtins-base.def     |   1 +
 gcc/config/aarch64/aarch64-sve-builtins.cc    | 157 ++++++++-----
 gcc/config/aarch64/aarch64-sve-builtins.def   |   2 +
 gcc/config/aarch64/aarch64-sve-builtins.h     |   4 +-
 .../aarch64/sve/acle/general-c++/mangle_1.C   |   2 +
 .../aarch64/sve/acle/general-c++/mangle_2.C   |   2 +
 .../aarch64/sve/acle/general-c++/svcount_1.C  |  10 +
 .../aarch64/sve/acle/asm/reinterpret_b.c      |  20 ++
 .../aarch64/sve/acle/asm/test_sve_acle.h      |  15 ++
 .../aarch64/sve/acle/general-c/load_1.c       |   4 +-
 .../aarch64/sve/acle/general-c/svcount_1.c    |  10 +
 .../sve/acle/general-c/unary_convert_1.c      |   8 +-
 .../aarch64/sve/acle/general/attributes_7.c   |   1 +
 .../gcc.target/aarch64/sve/pcs/annotate_1.c   |   4 +
 .../gcc.target/aarch64/sve/pcs/annotate_2.c   |   4 +
 .../gcc.target/aarch64/sve/pcs/args_12.c      | 214 ++++++++++++++++++
 17 files changed, 402 insertions(+), 64 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svcount_1.C
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/acle/asm/reinterpret_b.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/svcount_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/pcs/args_12.c
diff mbox series

Patch

diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index a219c88085a..89035135a38 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -2153,8 +2153,9 @@  public:
 
     /* Punt to rtl if the effect of the reinterpret on registers does not
        conform to GCC's endianness model.  */
-    if (!targetm.can_change_mode_class (f.vector_mode (0),
-					f.vector_mode (1), FP_REGS))
+    if (GET_MODE_CLASS (f.vector_mode (0)) != MODE_VECTOR_BOOL
+	&& !targetm.can_change_mode_class (f.vector_mode (0),
+					   f.vector_mode (1), FP_REGS))
       return NULL;
 
     /* Otherwise svreinterpret corresponds directly to a VIEW_CONVERT_EXPR
@@ -2168,6 +2169,9 @@  public:
   expand (function_expander &e) const override
   {
     machine_mode mode = e.tuple_mode (0);
+    /* Handle svbool_t <-> svcount_t.  */
+    if (mode == e.tuple_mode (1))
+      return e.args[0];
     return e.use_exact_insn (code_for_aarch64_sve_reinterpret (mode));
   }
 };
diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.def b/gcc/config/aarch64/aarch64-sve-builtins-base.def
index ac53f35220d..a742c7bbc56 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.def
@@ -198,6 +198,7 @@  DEF_SVE_FUNCTION (svrecpe, unary, all_float, none)
 DEF_SVE_FUNCTION (svrecps, binary, all_float, none)
 DEF_SVE_FUNCTION (svrecpx, unary, all_float, mxz)
 DEF_SVE_FUNCTION_GS (svreinterpret, reinterpret, reinterpret, x1234, none)
+DEF_SVE_FUNCTION (svreinterpret, reinterpret, reinterpret_b, none)
 DEF_SVE_FUNCTION (svrev, unary, all_data, none)
 DEF_SVE_FUNCTION (svrev, unary_pred, all_pred, none)
 DEF_SVE_FUNCTION (svrevb, unary, hsd_integer, mxz)
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc
index a40d448685d..e32f0f8f903 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -430,6 +430,12 @@  CONSTEXPR const group_suffix_info group_suffixes[] = {
   TYPES_reinterpret1 (D, u32), \
   TYPES_reinterpret1 (D, u64)
 
+/* _b_c
+   _c_b.  */
+#define TYPES_reinterpret_b(S, D) \
+  D (b, c), \
+  D (c, b)
+
 /* { _b8 _b16 _b32 _b64 } x { _s32 _s64 }
 			    { _u32 _u64 } */
 #define TYPES_while1(D, bn) \
@@ -579,6 +585,7 @@  DEF_SVE_TYPES_ARRAY (cvt_narrow_s);
 DEF_SVE_TYPES_ARRAY (cvt_narrow);
 DEF_SVE_TYPES_ARRAY (inc_dec_n);
 DEF_SVE_TYPES_ARRAY (reinterpret);
+DEF_SVE_TYPES_ARRAY (reinterpret_b);
 DEF_SVE_TYPES_ARRAY (while);
 DEF_SVE_TYPES_ARRAY (all_za);
 DEF_SVE_TYPES_ARRAY (d_za);
@@ -3789,6 +3796,49 @@  function_expander::expand ()
   return base->expand (*this);
 }
 
+/* Return a structure type that contains a single field of type FIELD_TYPE.
+   The field is called __val, but that's an internal detail rather than
+   an exposed part of the API.  */
+static tree
+wrap_type_in_struct (tree field_type)
+{
+  tree field = build_decl (input_location, FIELD_DECL,
+			   get_identifier ("__val"), field_type);
+  tree struct_type = lang_hooks.types.make_type (RECORD_TYPE);
+  DECL_FIELD_CONTEXT (field) = struct_type;
+  TYPE_FIELDS (struct_type) = field;
+  make_type_sizeless (struct_type);
+  layout_type (struct_type);
+  return struct_type;
+}
+
+/* Register a built-in TYPE_DECL called NAME for TYPE.  This is used/needed
+   when TYPE is a structure type.  */
+static void
+register_type_decl (tree type, const char *name)
+{
+  tree decl = build_decl (input_location, TYPE_DECL,
+			  get_identifier (name), type);
+  TYPE_NAME (type) = decl;
+  TYPE_STUB_DECL (type) = decl;
+  lang_hooks.decls.pushdecl (decl);
+  /* ??? Undo the effect of set_underlying_type for C.  The C frontend
+     doesn't recognize DECL as a built-in because (as intended) the decl has
+     a real location instead of BUILTINS_LOCATION.  The frontend therefore
+     treats the decl like a normal C "typedef struct foo foo;", expecting
+     the type for tag "struct foo" to have a dummy unnamed TYPE_DECL instead
+     of the named one we attached above.  It then sets DECL_ORIGINAL_TYPE
+     on the supposedly unnamed decl, creating a circularity that upsets
+     dwarf2out.
+
+     We don't want to follow the normal C model and create "struct foo"
+     tags for tuple types since (a) the types are supposed to be opaque
+     and (b) they couldn't be defined as a real struct anyway.  Treating
+     the TYPE_DECLs as "typedef struct foo foo;" without creating
+     "struct foo" would lead to confusing error messages.  */
+  DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
+}
+
 /* Register the built-in SVE ABI types, such as __SVBool_t.  */
 static void
 register_builtin_types ()
@@ -3799,48 +3849,63 @@  register_builtin_types ()
 
   for (unsigned int i = 0; i < NUM_VECTOR_TYPES; ++i)
     {
-      tree eltype = scalar_types[i];
       tree vectype;
       unsigned int num_zr = 0, num_pr = 0;
-      if (eltype == boolean_type_node)
+      if (vector_type_index (i) == VECTOR_TYPE_svcount_t)
 	{
-	  vectype = build_truth_vector_type_for_mode (BYTES_PER_SVE_VECTOR,
-						      VNx16BImode);
-	  gcc_assert (TYPE_MODE (vectype) == VNx16BImode
-		      && TYPE_MODE (vectype) == TYPE_MODE_RAW (vectype)
-		      && TYPE_ALIGN (vectype) == 16
-		      && known_eq (wi::to_poly_offset (TYPE_SIZE (vectype)),
-				   BYTES_PER_SVE_VECTOR));
+	  vectype = abi_vector_types[VECTOR_TYPE_svbool_t];
+	  vectype = wrap_type_in_struct (vectype);
 	  num_pr = 1;
 	}
       else
 	{
-	  scalar_mode elmode = SCALAR_TYPE_MODE (eltype);
-	  unsigned int elbytes = GET_MODE_SIZE (elmode);
-	  poly_uint64 nunits = exact_div (BYTES_PER_SVE_VECTOR, elbytes);
-	  machine_mode mode
-	    = aarch64_sve_data_mode (elmode, nunits).require ();
-	  vectype = build_vector_type_for_mode (eltype, mode);
-	  gcc_assert (VECTOR_MODE_P (TYPE_MODE (vectype))
-		      && TYPE_MODE (vectype) == mode
-		      && TYPE_MODE_RAW (vectype) == mode
-		      && TYPE_ALIGN (vectype) == 128
-		      && known_eq (wi::to_poly_offset (TYPE_SIZE (vectype)),
-				   BITS_PER_SVE_VECTOR));
-	  num_zr = 1;
+	  tree eltype = scalar_types[i];
+	  if (eltype == boolean_type_node)
+	    {
+	      vectype = build_truth_vector_type_for_mode (BYTES_PER_SVE_VECTOR,
+							  VNx16BImode);
+	      num_pr = 1;
+	    }
+	  else
+	    {
+	      scalar_mode elmode = SCALAR_TYPE_MODE (eltype);
+	      unsigned int elbytes = GET_MODE_SIZE (elmode);
+	      poly_uint64 nunits = exact_div (BYTES_PER_SVE_VECTOR, elbytes);
+	      machine_mode mode
+		= aarch64_sve_data_mode (elmode, nunits).require ();
+	      vectype = build_vector_type_for_mode (eltype, mode);
+	      auto size = wi::to_poly_offset (TYPE_SIZE (vectype));
+	      gcc_assert (VECTOR_MODE_P (TYPE_MODE (vectype))
+			  && TYPE_MODE (vectype) == mode
+			  && TYPE_MODE_RAW (vectype) == mode
+			  && TYPE_ALIGN (vectype) == 128
+			  && known_eq (size, BITS_PER_SVE_VECTOR));
+	      num_zr = 1;
+	    }
+	  vectype = build_distinct_type_copy (vectype);
+	  gcc_assert (vectype == TYPE_MAIN_VARIANT (vectype));
+	  SET_TYPE_STRUCTURAL_EQUALITY (vectype);
+	  TYPE_ARTIFICIAL (vectype) = 1;
+	  TYPE_INDIVISIBLE_P (vectype) = 1;
+	  make_type_sizeless (vectype);
+	}
+      if (num_pr)
+	{
+	  auto size = wi::to_poly_offset (TYPE_SIZE (vectype));
+	  gcc_assert (TYPE_MODE (vectype) == VNx16BImode
+		      && TYPE_MODE (vectype) == TYPE_MODE_RAW (vectype)
+		      && TYPE_ALIGN (vectype) == 16
+		      && known_eq (size, BYTES_PER_SVE_VECTOR));
 	}
-      vectype = build_distinct_type_copy (vectype);
-      gcc_assert (vectype == TYPE_MAIN_VARIANT (vectype));
-      SET_TYPE_STRUCTURAL_EQUALITY (vectype);
-      TYPE_ARTIFICIAL (vectype) = 1;
-      TYPE_INDIVISIBLE_P (vectype) = 1;
       add_sve_type_attribute (vectype, num_zr, num_pr,
 			      vector_types[i].mangled_name,
 			      vector_types[i].acle_name);
-      make_type_sizeless (vectype);
       abi_vector_types[i] = vectype;
-      lang_hooks.types.register_builtin_type (vectype,
-					      vector_types[i].abi_name);
+      if (TREE_CODE (vectype) == RECORD_TYPE)
+	register_type_decl (vectype, vector_types[i].abi_name);
+      else
+	lang_hooks.types.register_builtin_type (vectype,
+						vector_types[i].abi_name);
     }
 }
 
@@ -3884,8 +3949,6 @@  register_vector_type (vector_type_index type)
 static void
 register_tuple_type (unsigned int num_vectors, vector_type_index type)
 {
-  tree tuple_type = lang_hooks.types.make_type (RECORD_TYPE);
-
   /* Work out the structure name.  */
   char buffer[sizeof ("svbfloat16x4_t")];
   const char *vector_type_name = vector_types[type].acle_name;
@@ -3912,37 +3975,13 @@  register_tuple_type (unsigned int num_vectors, vector_type_index type)
 	      && TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type)
 	      && TYPE_ALIGN (array_type) == 128);
 
-  tree field = build_decl (input_location, FIELD_DECL,
-			   get_identifier ("__val"), array_type);
-  DECL_FIELD_CONTEXT (field) = tuple_type;
-  TYPE_FIELDS (tuple_type) = field;
+  tree tuple_type = wrap_type_in_struct (array_type);
   add_sve_type_attribute (tuple_type, num_vectors, 0, NULL, buffer);
-  make_type_sizeless (tuple_type);
-  layout_type (tuple_type);
   gcc_assert (VECTOR_MODE_P (TYPE_MODE (tuple_type))
 	      && TYPE_MODE_RAW (tuple_type) == TYPE_MODE (tuple_type)
 	      && TYPE_ALIGN (tuple_type) == 128);
 
-  tree decl = build_decl (input_location, TYPE_DECL,
-			  get_identifier (buffer), tuple_type);
-  TYPE_NAME (tuple_type) = decl;
-  TYPE_STUB_DECL (tuple_type) = decl;
-  lang_hooks.decls.pushdecl (decl);
-  /* ??? Undo the effect of set_underlying_type for C.  The C frontend
-     doesn't recognize DECL as a built-in because (as intended) the decl has
-     a real location instead of BUILTINS_LOCATION.  The frontend therefore
-     treats the decl like a normal C "typedef struct foo foo;", expecting
-     the type for tag "struct foo" to have a dummy unnamed TYPE_DECL instead
-     of the named one we attached above.  It then sets DECL_ORIGINAL_TYPE
-     on the supposedly unnamed decl, creating a circularity that upsets
-     dwarf2out.
-
-     We don't want to follow the normal C model and create "struct foo"
-     tags for tuple types since (a) the types are supposed to be opaque
-     and (b) they couldn't be defined as a real struct anyway.  Treating
-     the TYPE_DECLs as "typedef struct foo foo;" without creating
-     "struct foo" would lead to confusing error messages.  */
-  DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
+  register_type_decl (tuple_type, buffer);
 
   acle_vector_types[num_vectors - 1][type] = tuple_type;
 }
@@ -3992,7 +4031,7 @@  handle_arm_sve_h ()
     {
       vector_type_index type = vector_type_index (type_i);
       register_vector_type (type);
-      if (type != VECTOR_TYPE_svbool_t)
+      if (scalar_types[type_i] != boolean_type_node)
 	for (unsigned int count = 2; count <= MAX_TUPLE_SIZE; ++count)
 	  register_tuple_type (count, type);
     }
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def
index 5824dc797f9..297904f3e47 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins.def
@@ -84,6 +84,7 @@  DEF_SVE_MODE (u64offset, none, svuint64_t, bytes)
 DEF_SVE_MODE (vnum, none, none, vectors)
 
 DEF_SVE_TYPE (svbool_t, 10, __SVBool_t, boolean_type_node)
+DEF_SVE_TYPE (svcount_t, 11, __SVCount_t, boolean_type_node)
 DEF_SVE_TYPE (svbfloat16_t, 14, __SVBfloat16_t, bfloat16_type_node)
 DEF_SVE_TYPE (svfloat16_t, 13, __SVFloat16_t, aarch64_fp16_type_node)
 DEF_SVE_TYPE (svfloat32_t, 13, __SVFloat32_t, float_type_node)
@@ -106,6 +107,7 @@  DEF_SVE_TYPE_SUFFIX (b16, svbool_t, bool, 16, VNx8BImode)
 DEF_SVE_TYPE_SUFFIX (b32, svbool_t, bool, 32, VNx4BImode)
 DEF_SVE_TYPE_SUFFIX (b64, svbool_t, bool, 64, VNx2BImode)
 DEF_SVE_TYPE_SUFFIX (bf16, svbfloat16_t, bfloat, 16, VNx8BFmode)
+DEF_SVE_TYPE_SUFFIX (c, svcount_t, count, 8, VNx16BImode)
 DEF_SVE_TYPE_SUFFIX (f16, svfloat16_t, float, 16, VNx8HFmode)
 DEF_SVE_TYPE_SUFFIX (f32, svfloat32_t, float, 32, VNx4SFmode)
 DEF_SVE_TYPE_SUFFIX (f64, svfloat64_t, float, 64, VNx2DFmode)
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.h b/gcc/config/aarch64/aarch64-sve-builtins.h
index 1cd31d2d733..51774825c23 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.h
+++ b/gcc/config/aarch64/aarch64-sve-builtins.h
@@ -152,11 +152,13 @@  enum predication_index
 };
 
 /* Classifies element types, based on type suffixes with the bit count
-   removed.  */
+   removed.  "count" isn't really an element type, but we pretend it is
+   for consistency.  */
 enum type_class_index
 {
   TYPE_bool,
   TYPE_bfloat,
+  TYPE_count,
   TYPE_float,
   TYPE_signed,
   TYPE_unsigned,
diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C
index 36dab3c9b71..2ad0c7f9838 100644
--- a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C
+++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C
@@ -15,6 +15,7 @@  void f10(svfloat16_t) {}
 void f11(svfloat32_t) {}
 void f12(svfloat64_t) {}
 void f13(svbfloat16_t) {}
+void f14(svcount_t) {}
 
 /* { dg-final { scan-assembler "_Z2f1u10__SVBool_t:" } } */
 /* { dg-final { scan-assembler "_Z2f2u10__SVInt8_t:" } } */
@@ -29,3 +30,4 @@  void f13(svbfloat16_t) {}
 /* { dg-final { scan-assembler "_Z3f11u13__SVFloat32_t:" } } */
 /* { dg-final { scan-assembler "_Z3f12u13__SVFloat64_t:" } } */
 /* { dg-final { scan-assembler "_Z3f13u14__SVBfloat16_t:" } } */
+/* { dg-final { scan-assembler "_Z3f14u11__SVCount_t:" } } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C
index ad4aaee291f..c8bfcc5a9c2 100644
--- a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C
+++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C
@@ -13,6 +13,7 @@  void f10(__SVFloat16_t) {}
 void f11(__SVFloat32_t) {}
 void f12(__SVFloat64_t) {}
 void f13(__SVBfloat16_t) {}
+void f14(__SVCount_t) {}
 
 /* { dg-final { scan-assembler "_Z2f1u10__SVBool_t:" } } */
 /* { dg-final { scan-assembler "_Z2f2u10__SVInt8_t:" } } */
@@ -27,3 +28,4 @@  void f13(__SVBfloat16_t) {}
 /* { dg-final { scan-assembler "_Z3f11u13__SVFloat32_t:" } } */
 /* { dg-final { scan-assembler "_Z3f12u13__SVFloat64_t:" } } */
 /* { dg-final { scan-assembler "_Z3f13u14__SVBfloat16_t:" } } */
+/* { dg-final { scan-assembler "_Z3f14u11__SVCount_t:" } } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svcount_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svcount_1.C
new file mode 100644
index 00000000000..9eac65aafff
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svcount_1.C
@@ -0,0 +1,10 @@ 
+#include <arm_sve.h>
+
+svbool_t f1 (svcount_t x) { return x; } // { dg-error {cannot convert 'svcount_t' to 'svbool_t' in return} }
+svcount_t f2 (svbool_t x) { return x; } // { dg-error {cannot convert 'svbool_t' to 'svcount_t' in return} }
+void f3 (svbool_t *p, svcount_t x) { *p = x; } // { dg-error {cannot convert 'svcount_t' to 'svbool_t' in assignment} }
+void f4 (svcount_t *p, svbool_t x) { *p = x; } // { dg-error {cannot convert 'svbool_t' to 'svcount_t' in assignment} }
+svbool_t *f5 (svcount_t *p) { return p; } // { dg-error {cannot convert} }
+svcount_t *f6 (svbool_t *p) { return p; } // { dg-error {cannot convert} }
+svbool_t f7 (svcount_t x) { return (svbool_t) x; } // { dg-error {invalid cast from type 'svcount_t' to type 'svbool_t'} }
+svcount_t f8 (svbool_t x) { return (svcount_t) x; } // { dg-error {invalid cast from type 'svbool_t' to type 'svcount_t'} }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/reinterpret_b.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/reinterpret_b.c
new file mode 100644
index 00000000000..57736ecb6c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/reinterpret_b.c
@@ -0,0 +1,20 @@ 
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** reinterpret_b_c_tied1:
+**	ret
+*/
+TEST_DUAL_P_REV (reinterpret_b_c_tied1, svbool_t, svcount_t,
+		 p0_res = svreinterpret_b_c (p0),
+		 p0_res = svreinterpret_b (p0))
+
+/*
+** reinterpret_b_c_untied:
+**	mov	p0\.b, p2\.b
+**	ret
+*/
+TEST_DUAL_P (reinterpret_b_c_untied, svbool_t, svcount_t,
+	     p0 = svreinterpret_b_c (p2),
+	     p0 = svreinterpret_b (p2))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
index 84925b9bd48..5ce0be5947b 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
@@ -85,6 +85,21 @@ 
     return z0_res;						\
   }
 
+#define TEST_DUAL_P(NAME, TYPE1, TYPE2, CODE1, CODE2)		\
+  PROTO (NAME, TYPE1, (TYPE1 p0, TYPE1 p1, TYPE2 p2, TYPE2 p3))	\
+  {								\
+    INVOKE (CODE1, CODE2);					\
+    return p0;							\
+  }
+
+#define TEST_DUAL_P_REV(NAME, TYPE1, TYPE2, CODE1, CODE2)	\
+  PROTO (NAME, TYPE1, (TYPE2 p0, TYPE2 p1, TYPE1 p2, TYPE1 p3))	\
+  {								\
+    TYPE1 p0_res;						\
+    INVOKE (CODE1, CODE2);					\
+    return p0_res;						\
+  }
+
 #define TEST_TRIPLE_Z(NAME, TYPE1, TYPE2, TYPE3, CODE1, CODE2)	\
   PROTO (NAME, TYPE1, (TYPE1 z0, TYPE1 z1, TYPE2 z2, TYPE2 z3,	\
 		       TYPE3 z4, TYPE3 z5,			\
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c
index 784fdc317e6..564295a87f3 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c
@@ -6,12 +6,14 @@ 
 struct s { signed char x; };
 
 svuint8_t
-f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr,
+f1 (svbool_t pg, svcount_t pn,
+    signed char *s8_ptr, void *void_ptr, struct s *s_ptr,
     float *f32_ptr, _Complex float *cf32_ptr, int **ptr_ptr)
 {
   svld1 (pg); /* { dg-error {too few arguments to function 'svld1'} } */
   svld1 (pg, s8_ptr, 0); /* { dg-error {too many arguments to function 'svld1'} } */
   svld1 (0, s8_ptr); /* { dg-error {passing 'int' to argument 1 of 'svld1', which expects 'svbool_t'} } */
+  svld1 (pn, s8_ptr); /* { dg-error {passing 'svcount_t' to argument 1 of 'svld1', which expects 'svbool_t'} } */
   svld1 (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svld1', which expects a pointer type} } */
   svld1 (pg, (int32_t *) 0);
   svld1 (pg, void_ptr); /* { dg-error {passing 'void \*' to argument 2 of 'svld1', but 'void' is not a valid SVE element type} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/svcount_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/svcount_1.c
new file mode 100644
index 00000000000..920d37e4ce7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/svcount_1.c
@@ -0,0 +1,10 @@ 
+#include <arm_sve.h>
+
+svbool_t f1 (svcount_t x) { return x; } /* { dg-error {incompatible types} } */
+svcount_t f2 (svbool_t x) { return x; } /* { dg-error {incompatible types} } */
+void f3 (svbool_t *p, svcount_t x) { *p = x; } /* { dg-error {incompatible types} } */
+void f4 (svcount_t *p, svbool_t x) { *p = x; } /* { dg-error {incompatible types} } */
+svbool_t *f5 (svcount_t *p) { return p; } /* { dg-error {incompatible return type} } */
+svcount_t *f6 (svbool_t *p) { return p; } /* { dg-error {incompatible return type} } */
+svbool_t f7 (svcount_t x) { return (svbool_t) x; } /* { dg-error {conversion to non-scalar} } */
+svcount_t f8 (svbool_t x) { return (svcount_t) x; } /* { dg-error {conversion to non-scalar} } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c
index f59ad590ba4..b7258e434db 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c
@@ -4,7 +4,7 @@  void
 test (svbool_t pg, svint8_t s8, svuint8_t u8,
       svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32,
       svint64_t s64, svuint64_t u64, svfloat16_t f16, svfloat32_t f32,
-      svfloat64_t f64)
+      svfloat64_t f64, svcount_t pn)
 {
   svcvt_f64_x (pg); /* { dg-error {too few arguments to function 'svcvt_f64_x'} } */
   svcvt_f64_x (pg, s32, 0); /* { dg-error {too many arguments to function 'svcvt_f64_x'} } */
@@ -70,4 +70,10 @@  test (svbool_t pg, svint8_t s8, svuint8_t u8,
   svcvt_u16_x (pg, f16);
   svcvt_u16_x (pg, f32); /* { dg-error {'svcvt_u16_x' has no form that takes 'svfloat32_t' arguments} } */
   svcvt_u16_x (pg, f64); /* { dg-error {'svcvt_u16_x' has no form that takes 'svfloat64_t' arguments} } */
+
+  svreinterpret_b (pg); /* { dg-error {'svreinterpret_b' has no form that takes 'svbool_t' arguments} } */
+  svreinterpret_b (pn);
+
+  svreinterpret_c (pg);
+  svreinterpret_c (pn); /* { dg-error {'svreinterpret_c' has no form that takes 'svcount_t' arguments} } */
 }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c
index 5658a206fa3..edfadb8da38 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c
@@ -27,6 +27,7 @@  typedef svint32x2_t bad_type_6 __attribute__ ((arm_sve_vector_bits (N))); // { d
 typedef svint8_t bad_type_7 __attribute__ ((arm_sve_vector_bits (N))) __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to type 'svint8_t __attribute__\(\(arm_sve_vector_bits\([0-9]+\)\)\)', which already has a size} }
 typedef fixed_bool_t bad_type_8 __attribute__ ((arm_sve_vector_bits (N))) __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to type 'fixed_bool_t' {aka 'svbool_t __attribute__\(\(arm_sve_vector_bits\([0-9]+\)\)\)'}, which already has a size} }
 typedef gnu_int8_t bad_type_9 __attribute__ ((arm_sve_vector_bits (N))) __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to non-SVE type 'gnu_int8_t'} }
+typedef svcount_t bad_type_10 __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to non-vector type 'svcount_t'} }
 
 void
 f (int c)
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_1.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_1.c
index 12ae7678948..c3ac692d7ff 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_1.c
@@ -4,6 +4,8 @@ 
 
 svbool_t ret_b (void) { return svptrue_b8 (); }
 
+svcount_t ret_c (svcount_t *ptr) { return *ptr; }
+
 svint8_t ret_s8 (void) { return svdup_s8 (0); }
 svint16_t ret_s16 (void) { return svdup_s16 (0); }
 svint32_t ret_s32 (void) { return svdup_s32 (0); }
@@ -58,6 +60,8 @@  svfloat64x4_t ret_f64x4 (void) { return svundef4_f64 (); }
 
 /* { dg-final { scan-assembler {\t\.variant_pcs\tret_b\n} } } */
 
+/* { dg-final { scan-assembler {\t\.variant_pcs\tret_c\n} } } */
+
 /* { dg-final { scan-assembler {\t\.variant_pcs\tret_s8\n} } } */
 /* { dg-final { scan-assembler {\t\.variant_pcs\tret_s16\n} } } */
 /* { dg-final { scan-assembler {\t\.variant_pcs\tret_s32\n} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_2.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_2.c
index 9f0741e3c26..c3508735fc4 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/annotate_2.c
@@ -4,6 +4,8 @@ 
 
 void fn_b (svbool_t x) {}
 
+void fn_c (svcount_t x) {}
+
 void fn_s8 (svint8_t x) {}
 void fn_s16 (svint16_t x) {}
 void fn_s32 (svint32_t x) {}
@@ -58,6 +60,8 @@  void fn_f64x4 (svfloat64x4_t x) {}
 
 /* { dg-final { scan-assembler {\t\.variant_pcs\tfn_b\n} } } */
 
+/* { dg-final { scan-assembler {\t\.variant_pcs\tfn_c\n} } } */
+
 /* { dg-final { scan-assembler {\t\.variant_pcs\tfn_s8\n} } } */
 /* { dg-final { scan-assembler {\t\.variant_pcs\tfn_s16\n} } } */
 /* { dg-final { scan-assembler {\t\.variant_pcs\tfn_s32\n} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/args_12.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/args_12.c
new file mode 100644
index 00000000000..a589484b394
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/args_12.c
@@ -0,0 +1,214 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fno-stack-clash-protection -g" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sve.h>
+
+/*
+** callee_1:
+**	mov	p0\.b, p3\.b
+**	ret
+*/
+svcount_t __attribute__ ((noipa))
+callee_1 (svcount_t p0, svcount_t p1, svcount_t p2, svcount_t p3)
+{
+  return p3;
+}
+
+/*
+** callee_2:
+**	str	p0, \[x0\]
+**	str	p1, \[x1\]
+**	str	p2, \[x2\]
+**	str	p3, \[x3\]
+**	ret
+*/
+void __attribute__ ((noipa))
+callee_2 (svcount_t p0, svcount_t p1, svcount_t p2, svcount_t p3,
+	  svcount_t *ptr0, svcount_t *ptr1, svcount_t *ptr2, svcount_t *ptr3)
+{
+  *ptr0 = p0;
+  *ptr1 = p1;
+  *ptr2 = p2;
+  *ptr3 = p3;
+}
+
+/*
+** callee_3:
+**	str	p3, \[x0\]
+**	ret
+*/
+void __attribute__ ((noipa))
+callee_3 (svbool_t p0, svbool_t p1, svbool_t p2, svcount_t p3, svcount_t *ptr)
+{
+  *ptr = p3;
+}
+
+/*
+** callee_4:
+**	str	p3, \[x0\]
+**	ret
+*/
+void __attribute__ ((noipa))
+callee_4 (svcount_t p0, svcount_t p1, svcount_t p2, svbool_t p3, svbool_t *ptr)
+{
+  *ptr = p3;
+}
+
+/*
+** callee_5:
+**	ldr	p0, \[x0\]
+**	ret
+*/
+svcount_t __attribute__ ((noipa))
+callee_5 (svcount_t p0, svcount_t p1, svcount_t p2, svcount_t p3,
+	  svcount_t p4)
+{
+  return p4;
+}
+
+/*
+** callee_6:
+**	ldr	p0, \[x0\]
+**	ret
+*/
+svcount_t __attribute__ ((noipa))
+callee_6 (svcount_t p0, svcount_t p1, svcount_t p2, svcount_t p3,
+	  svcount_t p4, int x1, int x2, int x3, int x4, int x5, int x6, int x7,
+	  int x8)
+{
+  return p4;
+}
+
+/*
+** callee_7:
+**	ldr	(x[0-9]+), \[sp\]
+**	ldr	p0, \[\1\]
+**	ret
+*/
+svcount_t __attribute__ ((noipa))
+callee_7 (svcount_t p0, svcount_t p1, svcount_t p2, svcount_t p3,
+	  int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7,
+	  svcount_t p4)
+{
+  return p4;
+}
+
+/*
+** caller_1:
+**	...
+**	ldr	p0, \[x0\]
+**	ldr	p1, \[x1\]
+**	ldr	p2, \[x2\]
+**	ldr	p3, \[x3\]
+**	bl	callee_1
+**	...
+**	str	p0, .*
+**	...
+*/
+void __attribute__ ((noipa))
+caller_1 (volatile svcount_t *ptr0, volatile svcount_t *ptr1,
+	  volatile svcount_t *ptr2, volatile svcount_t *ptr3,
+	  svcount_t *ptr4)
+{
+  svcount_t p0 = *ptr0;
+  svcount_t p1 = *ptr1;
+  svcount_t p2 = *ptr2;
+  svcount_t p3 = *ptr3;
+  *ptr4 = callee_1 (p0, p1, p2, p3);
+}
+
+/*
+** caller_3:
+**	...
+**	ldr	p0, \[x1\]
+**	ldr	p1, \[x2\]
+**	ldr	p2, \[x3\]
+**	ldr	p3, \[x4\]
+**	bl	callee_3
+**	...
+*/
+void __attribute__ ((noipa))
+caller_3 (svcount_t *ptr,
+	  volatile svbool_t *ptr0, volatile svbool_t *ptr1,
+	  volatile svbool_t *ptr2, volatile svcount_t *ptr3)
+{
+  svbool_t p0 = *ptr0;
+  svbool_t p1 = *ptr1;
+  svbool_t p2 = *ptr2;
+  svcount_t p3 = *ptr3;
+  callee_3 (p0, p1, p2, p3, ptr);
+}
+
+/*
+** caller_4:
+**	...
+**	ldr	p0, \[x1\]
+**	ldr	p1, \[x2\]
+**	ldr	p2, \[x3\]
+**	ldr	p3, \[x4\]
+**	bl	callee_4
+**	...
+*/
+void __attribute__ ((noipa))
+caller_4 (svbool_t *ptr,
+	  volatile svcount_t *ptr0, volatile svcount_t *ptr1,
+	  volatile svcount_t *ptr2, volatile svbool_t *ptr3)
+{
+  svcount_t p0 = *ptr0;
+  svcount_t p1 = *ptr1;
+  svcount_t p2 = *ptr2;
+  svbool_t p3 = *ptr3;
+  callee_4 (p0, p1, p2, p3, ptr);
+}
+
+/*
+** caller_5:
+**	...
+**	ldr	p0, \[x1\]
+**	ldr	p1, \[x2\]
+**	ldr	p2, \[x3\]
+**	ldr	p3, \[x4\]
+**	...
+**	mov	x0, sp
+**	...
+**	str	p[0-9]+, \[(?:x0|sp)\]
+**	...
+**	bl	callee_5
+**	...
+**	str	p0, .*
+**	...
+*/
+void __attribute__ ((noipa))
+caller_5 (svcount_t *ptr,
+	  volatile svcount_t *ptr0, volatile svcount_t *ptr1,
+	  volatile svcount_t *ptr2, volatile svcount_t *ptr3,
+	  volatile svcount_t *ptr4)
+{
+  svcount_t p0 = *ptr0;
+  svcount_t p1 = *ptr1;
+  svcount_t p2 = *ptr2;
+  svcount_t p3 = *ptr3;
+  svcount_t p4 = *ptr4;
+  *ptr = callee_5 (p0, p1, p2, p3, p4);
+}
+
+/*
+** caller_7:
+**	...
+**	ldr	(p[0-9]+), \[x2\]
+**	...
+**	str	\1, \[(x[0-9]+)\]
+**	...
+**	str	\2, \[sp\]
+**	...
+**	bl	callee_7
+**	...
+*/
+void __attribute__ ((noipa))
+caller_7 (svcount_t *ptr, volatile svcount_t *ptr0, volatile svcount_t *ptr1)
+{
+  svcount_t p0 = *ptr0;
+  svcount_t p1 = *ptr1;
+  *ptr = callee_7 (p0, p0, p0, p0, 0, 0, 0, 0, 0, 0, 0, 0, p1);
+}