From: Kyrylo Tkachov <[email protected]>

This is an alternative to 
https://gcc.gnu.org/pipermail/gcc-patches/2026-November/738269.html
after feedback from Andrea

TARGET_FNTYPE_ABI is called very often from RTL passes (fndecl_abi and
insn_callee_abi, via reg_set_p, IRA, df, rtl-ssa, cselib and others).
aarch64_fntype_abi runs aarch64_returns_value_in_sve_regs_p and
aarch64_takes_arguments_in_sve_regs_p on every call.  The latter sets up
a CUMULATIVE_ARGS, applies the pass-by-reference rules and runs
pure_scalable_type_info::analyze on every argument type, which is wasted
work for most function types.  In a perf profile of compiling fmt at -O3,
aarch64_fntype_abi accounts for about 2.5% of cc1plus instructions.

Add aarch64_fntype_may_use_pst_p, which applies the existing
aarch64_some_values_include_pst_objects_p to the return type and to each
argument type.  A function type for which none of them can include an
object of Pure Scalable Type cannot use the SVE PCS, so the existing
checks are only run for the others.  The test only looks at the types
and not at the current target options.

Do not return early when !TARGET_SVE.  The ABI of a callee must not
depend on the options of the caller, which can differ per function with
target attributes and pragmas, and TARGET_SVE also covers streaming mode.
SVE types are registered whatever the target options.  A function without
SVE that calls an SVE ABI function must still see the SVE ABI, because
aarch64_init_cumulative_args takes the PCS variant from
aarch64_fntype_abi and uses it to diagnose calls that require the SVE ISA
extension (see gcc.target/aarch64/sve/pcs/nosve_*.c).  Without it the call
would silently be emitted with the default ABI clobbers and without
.variant_pcs.  The type-based test above gives the same speedup for
functions that do not involve SVE types and keeps these diagnostics.

Do not cache the result in the function type either.  The spare type
flags are not safe to reuse.  TYPE_NEEDS_CONSTRUCTING is checked by
verify_type and by the LTO type comparison, and free-lang-data clears it.
The other candidate flags would carry stale values to the copies of a
function type that ipa-param-manipulation.cc, ipa-strub.cc and
omp-simd-clone.cc make before rewriting the argument list.  Clearing them
in these places needs a generic change in several files.  Caching saves a
further 0.4% of instructions at most on top of this patch.

The new test checks that calls to SVE ABI functions are compiled in the
same way from functions with different target options, and that a call to
a function with scalar arguments does not use the SVE ABI.

The test input is the C++ test suite of fmtlib/fmt
(https://github.com/fmtlib/fmt, commit 
bc13c6de390751ecf8daa1b1ce8f775d104fdc65),
built with CMake in Release mode (-O3 -DNDEBUG -std=gnu++11).

Compiling its 8 translation units on AArch64:
user-space instructions -1.9% in total, with printf-test.cc -2.2% and
format-test.cc -1.9%.

Bootstrapped and tested ona aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

        * config/aarch64/aarch64.cc (aarch64_fntype_may_use_pst_p): New
        function.
        (aarch64_fntype_abi): Use it.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/pcs/fntype_abi_target_1.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/config/aarch64/aarch64.cc                 | 30 ++++++-
 .../aarch64/sve/pcs/fntype_abi_target_1.c     | 80 +++++++++++++++++++
 2 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/sve/pcs/fntype_abi_target_1.c

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 730a1fee835..ba2be1bd329 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -2657,6 +2657,31 @@ aarch64_ms_variadic_abi (void)
   return ms_variadic_abi;
 }
 
+/* Return true if a function with type FNTYPE has a return type or an
+   argument type for which some value could include an object of Pure
+   Scalable Type.  This depends only on the types and not on the current
+   target options.  If it is false, FNTYPE cannot use the SVE PCS.  */
+
+static bool
+aarch64_fntype_may_use_pst_p (const_tree fntype)
+{
+  tree type = TREE_TYPE (fntype);
+  if (type == error_mark_node
+      || aarch64_some_values_include_pst_objects_p (type))
+    return true;
+
+  for (tree chain = TYPE_ARG_TYPES (fntype);
+       chain && chain != void_list_node;
+       chain = TREE_CHAIN (chain))
+    {
+      type = TREE_VALUE (chain);
+      if (type == error_mark_node
+         || aarch64_some_values_include_pst_objects_p (type))
+       return true;
+    }
+  return false;
+}
+
 /* Implement TARGET_FNTYPE_ABI.  */
 
 static const predefined_function_abi &
@@ -2673,8 +2698,9 @@ aarch64_fntype_abi (const_tree fntype)
       && !stdarg_p (fntype))
     return aarch64_preserve_none_abi ();
 
-  if (aarch64_returns_value_in_sve_regs_p (fntype)
-      || aarch64_takes_arguments_in_sve_regs_p (fntype))
+  if (aarch64_fntype_may_use_pst_p (fntype)
+      && (aarch64_returns_value_in_sve_regs_p (fntype)
+         || aarch64_takes_arguments_in_sve_regs_p (fntype)))
     return aarch64_sve_abi ();
 
   return default_function_abi;
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/fntype_abi_target_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/pcs/fntype_abi_target_1.c
new file mode 100644
index 00000000000..f4c39eefbbd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/fntype_abi_target_1.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv8.2-a" } */
+
+/* Check that calls to a function with an SVE register ABI are compiled
+   in the same way, whether SVE is enabled by a pragma or by an attribute
+   and whatever other extensions are enabled with it.  The ABI of a
+   function type does not depend on the target options.
+   Under the SVE ABI, p4-p15 are preserved by calls, so the predicates
+   that live across the calls below are held in them and are never
+   spilled.  */
+
+#include <arm_sve.h>
+
+svbool_t sve_callee (svbool_t);
+svbool_t (*sve_fn) (svbool_t);
+svint32x2_t tuple_callee (svint32x2_t);
+int scalar_callee (int, int *);
+
+int
+scalar_caller (int *x)
+{
+  return scalar_callee (x[0], x) + scalar_callee (x[1], x);
+}
+
+__attribute__((target ("+sve")))
+svint32x2_t
+tuple_caller (svint32x2_t x)
+{
+  return tuple_callee (tuple_callee (x));
+}
+
+#pragma GCC push_options
+#pragma GCC target "+sve"
+svbool_t
+pragma_sve (svbool_t p)
+{
+  svbool_t q = sve_callee (p);
+  return svand_z (p, q, sve_callee (q));
+}
+#pragma GCC pop_options
+
+#pragma GCC push_options
+#pragma GCC target "+sve2"
+svbool_t
+pragma_sve2 (svbool_t p)
+{
+  svbool_t q = sve_callee (p);
+  return svand_z (p, q, sve_callee (q));
+}
+#pragma GCC pop_options
+
+__attribute__((target ("+sve")))
+svbool_t
+attribute_sve (svbool_t p)
+{
+  svbool_t q = sve_callee (p);
+  return svand_z (p, q, sve_callee (q));
+}
+
+__attribute__((target ("+sve2")))
+svbool_t
+attribute_sve2 (svbool_t p)
+{
+  svbool_t q = sve_callee (p);
+  return svand_z (p, q, sve_callee (q));
+}
+
+__attribute__((target ("+sve2")))
+svbool_t
+indirect_sve2 (svbool_t p)
+{
+  svbool_t q = sve_fn (p);
+  return svand_z (p, q, sve_fn (q));
+}
+
+/* { dg-final { scan-assembler {\t\.variant_pcs\tsve_callee\n} } } */
+/* { dg-final { scan-assembler {\t\.variant_pcs\ttuple_callee\n} } } */
+/* { dg-final { scan-assembler-not {\t\.variant_pcs\tscalar_callee\n} } } */
+/* { dg-final { scan-assembler-times {\tmov\tp(?:[4-9]|1[0-5])\.b, p0\.b\n} 10 
} } */
+/* { dg-final { scan-assembler-not {\tstr\tp[0-3],} } } */
-- 
2.54.0 (Apple Git-157)

Reply via email to