On Thu, Nov 12, 2026, 12:19 AM <[email protected]> wrote:

> 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.


I think this analysis here is wrong.

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).


This seems like a diangostic should be done earlier rather than at this
point.
A function where sve is disable cannot call a function with sve types as
arguments or return types.


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