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