]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64: Mark SME functions as .variant_pcs [PR121414]
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 7 Aug 2025 14:15:00 +0000 (15:15 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 7 Aug 2025 14:15:00 +0000 (15:15 +0100)
Unlike base PCS functions, __arm_streaming and __arm_streaming_compatible
functions allow/require PSTATE.SM to be 1 on entry, so they need to
be treated as STO_AARCH64_VARIANT_PCS.

Similarly, functions that share ZA or ZT0 with their callers require
ZA to be active on entry, whereas the base PCS requires ZA to be
dormant or off.  These functions too need to be marked as having
a variant PCS.

gcc/
PR target/121414
* config/aarch64/aarch64.cc (aarch64_is_variant_pcs): New function,
split out from...
(aarch64_asm_output_variant_pcs): ...here.  Handle various types
of SME function type.

gcc/testsuite/
PR target/121414
* gcc.target/aarch64/sme/pr121414_1.c: New test.

gcc/config/aarch64/aarch64.cc
gcc/testsuite/gcc.target/aarch64/sme/pr121414_1.c [new file with mode: 0644]

index d30c9c75e425a8f5f4cfbf7f2453982afc395b16..2dbaf4a8e59b4e9a04e478e5f325940deea234ce 100644 (file)
@@ -25435,20 +25435,41 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
    return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
 }
 
+/* Return true if function declaration FNDECL needs to be marked as
+   having a variant PCS.  */
+
+static bool
+aarch64_is_variant_pcs (tree fndecl)
+{
+  /* Check for ABIs that preserve more registers than usual.  */
+  arm_pcs pcs = (arm_pcs) fndecl_abi (fndecl).id ();
+  if (pcs == ARM_PCS_SIMD || pcs == ARM_PCS_SVE)
+    return true;
+
+  /* Check for ABIs that allow PSTATE.SM to be 1 on entry.  */
+  tree fntype = TREE_TYPE (fndecl);
+  if (aarch64_fntype_pstate_sm (fntype) != AARCH64_ISA_MODE_SM_OFF)
+    return true;
+
+  /* Check for ABIs that require PSTATE.ZA to be 1 on entry, either because
+     of ZA or ZT0.  */
+  if (aarch64_fntype_pstate_za (fntype) != 0)
+    return true;
+
+  return false;
+}
+
 /* Output .variant_pcs for aarch64_vector_pcs function symbols.  */
 
 static void
 aarch64_asm_output_variant_pcs (FILE *stream, const tree decl, const char* name)
 {
-  if (TREE_CODE (decl) == FUNCTION_DECL)
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && aarch64_is_variant_pcs (decl))
     {
-      arm_pcs pcs = (arm_pcs) fndecl_abi (decl).id ();
-      if (pcs == ARM_PCS_SIMD || pcs == ARM_PCS_SVE)
-       {
-         fprintf (stream, "\t.variant_pcs\t");
-         assemble_name (stream, name);
-         fprintf (stream, "\n");
-       }
+      fprintf (stream, "\t.variant_pcs\t");
+      assemble_name (stream, name);
+      fprintf (stream, "\n");
     }
 }
 
diff --git a/gcc/testsuite/gcc.target/aarch64/sme/pr121414_1.c b/gcc/testsuite/gcc.target/aarch64/sme/pr121414_1.c
new file mode 100644 (file)
index 0000000..ad8600f
--- /dev/null
@@ -0,0 +1,27 @@
+#pragma GCC target "+sme2"
+
+void f1() __arm_streaming_compatible {}
+void f2() __arm_streaming {}
+void f3() __arm_in("za") {}
+void f4() __arm_out("za") {}
+void f5() __arm_inout("za") {}
+void f6() __arm_in("zt0") {}
+void f7() __arm_out("zt0") {}
+void f8() __arm_inout("zt0") {}
+
+__arm_locally_streaming void g1() {}
+__arm_new("za") void g2() {}
+__arm_new("zt0") void g3() {}
+
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf1\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf2\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf3\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf4\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf5\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf6\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf7\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\tf8\n} } } */
+
+/* { dg-final { scan-assembler-not {\t\.variant_pcs\tg1\n} } } */
+/* { dg-final { scan-assembler-not {\t\.variant_pcs\tg2\n} } } */
+/* { dg-final { scan-assembler-not {\t\.variant_pcs\tg3\n} } } */