Hi Alfie, > On 19 Nov 2025, at 10:57, Alfie Richards <[email protected]> wrote: > > The 11/18/2025 22:48, Iain Sandoe wrote: >> Hi Alfie, > > Hi Iain, > >> >>> On 6 Nov 2025, at 15:06, Alfie Richards <[email protected]> wrote: >> >>> Updated this patch to use r15 for argument passing (except on windows >>> targets) >>> which I missed. >> >> This causes this testcase: >> https://github.com/iains/gcc-darwin-arm64/blob/master-wip-apple-si/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d1.c >> >> to ICE on both aarch64-linux (cfarm185) and with my Darwin patches applied >> on arm64 macOS. >> >> during RTL pass: expand >> ../darwinpcs-d1.c: In function ‘call_use_no_stack’: >> ../darwinpcs-d1.c:53:3: internal compiler error: in get_pcs_arg_reg, at >> config/aarch64/aarch64.cc:7362 >> 53 | use_no_stack (0, 1, 2, 3, 4, 5, 6, 7, e, 'j', e, 'l'); >> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> 0x231f353 internal_error(char const*, ...) >> ../../src/gcc/diagnostic-global-context.cc:787 >> 0x84676f fancy_abort(char const*, int, char const*) >> ../../src/gcc/diagnostics/context.cc:1805 >> 0x150e933 get_pcs_arg_reg >> ../../src/gcc/config/aarch64/aarch64.cc:7362 >> 0x150e933 get_pcs_arg_reg >> ../../src/gcc/config/aarch64/aarch64.cc:7358 >> >> I think from comparing the conditions used in the main loop with the assert >> here >> the fix is: >> >> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc >> index 72a3961fa2f..d643a25e752 100644 >> --- a/gcc/config/aarch64/aarch64.cc >> +++ b/gcc/config/aarch64/aarch64.cc >> @@ -7388,7 +7388,7 @@ get_pcs_arg_reg (enum arm_pcs pcs, int num) >> { >> static const int ARM_PCS_PRESERVE_NONE_REGISTERS[] = >> PRESERVE_NONE_REGISTERS; >> - gcc_assert (num < num_pcs_arg_regs (pcs)); >> + gcc_assert (num <= num_pcs_arg_regs (pcs)); >> switch (pcs) >> { >> >> Does that seem reasonable, or did I miss some subtlety? > > That doesnt seem correct to me. For AAPCS R0-7 are used for argument passing > so num_pcs_arg_regs (pcs) is 8 so num < 8 seems to be the correct condition. > > The checks in aarch64_layout_arg are to check that > ncrn [next register to allocate] + nregs [number of registers required] <= > num_pcs_arg_regs (pcs) [number of argument passing registers available] > so the highest argument register requested used should be ncrn + nregs - 1 so > the strict less than should > still be valid. > > I will look more into the darwin PCS and how it differs from AAPCS but it > seems like its > an error in aarch64_layout_arg.
The darwinpcs differences are described here: https://github.com/iains/gcc-darwin-arm64/blob/master-wip-apple-si/gcc/config/aarch64/darwinpcs.md (which is markdown _not_ a machine description:) ) However, the test ICEs on aarch64-linux, and AFAICT the source code should be valid there too - so the glitch is not Darwin-specific. Iain > > Thanks, > Alfie > >> >> thanks >> Iain >> >>> >>> Updated the wording of the documentation and a comment slightly as it had >>> caused >>> some confusion. >>> >>> Reg tested on aarch64-linux-gnu. >>> >>> Okay for master? >>> >>> Alfie >>> >>> -- >8 -- >>> >>> When applied to a function preserve_none changes the procedure call standard >>> such that all registers except stack pointer, frame register, and link >>> register >>> are caller saved. Additionally, it changes the argument passing registers. >>> >>> PR target/118328 >>> >>> gcc/ChangeLog: >>> >>> * config/aarch64/aarch64.cc (handle_aarch64_vector_pcs_attribute): >>> Add handling for ARM_PCS_PRESERVE_NONE. >>> (aarch64_pcs_exclusions): New definition. >>> (aarch64_gnu_attributes): Add entry for preserve_none and add >>> aarch64_pcs_exclusions to aarch64_vector_pcs entry. >>> (aarch64_preserve_none_abi): New function. >>> (aarch64_fntype_abi): Add handling for preserve_none. >>> (aarch64_reg_save_mode): Add handling for ARM_PCS_PRESERVE_NONE. >>> (aarch64_hard_regno_call_part_clobbered): Add handling for >>> ARM_PCS_PRESERVE_NONE. >>> (num_pcs_arg_regs): New helper function. >>> (get_pcs_arg_reg): New helper function. >>> (aarch64_function_ok_for_sibcall): Add handling for ARM_PCS_PRESERVE_NONE. >>> (aarch64_layout_arg): Add preserve_none argument lauout.. >>> (function_arg_preserve_none_regno_p): New helper function. >>> (aarch64_function_arg): Update to handle preserve_none. >>> (function_arg_preserve_none_regno_p): Update logic for preserve_none. >>> (aarch64_expand_builtin_va_start): Add preserve_none layout. >>> (aarch64_setup_incoming_varargs): Add preserve_none layout. >>> (aarch64_is_variant_pcs): Update for case of ARM_PCS_PRESERVE_NONE. >>> (aarch64_comp_type_attributes): Add preserve_none. >>> * config/aarch64/aarch64.h (NUM_PRESERVE_NONE_ARG_REGS): New macro. >>> (PRESERVE_NONE_REGISTERS): New macro. >>> (enum arm_pcs): Add ARM_PCS_PRESERVE_NONE. >>> * doc/extend.texi (preserve_none): Add docs for new attribute. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * gcc.target/aarch64/preserve_none_1.c: New test. >>> * gcc.target/aarch64/preserve_none_mingw_1.c: New test. >>> * gcc.target/aarch64/preserve_none_2.c: New test. >>> * gcc.target/aarch64/preserve_none_3.c: New test. >>> * gcc.target/aarch64/preserve_none_4.c: New test. >>> * gcc.target/aarch64/preserve_none_5.c: New test. >>> * gcc.target/aarch64/preserve_none_6.c: New test. >>> --- >>> gcc/config/aarch64/aarch64.cc | 179 ++++++++++++++++-- >>> gcc/config/aarch64/aarch64.h | 27 +++ >>> gcc/doc/extend.texi | 21 ++ >>> .../gcc.target/aarch64/preserve_none_1.c | 143 ++++++++++++++ >>> .../gcc.target/aarch64/preserve_none_2.c | 49 +++++ >>> .../gcc.target/aarch64/preserve_none_3.c | 114 +++++++++++ >>> .../gcc.target/aarch64/preserve_none_4.c | 99 ++++++++++ >>> .../gcc.target/aarch64/preserve_none_5.c | 47 +++++ >>> .../gcc.target/aarch64/preserve_none_6.c | 76 ++++++++ >>> .../aarch64/preserve_none_mingw_1.c | 93 +++++++++ >>> 10 files changed, 828 insertions(+), 20 deletions(-) >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_1.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_2.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_3.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_4.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_5.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_6.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/preserve_none_mingw_1.c >>> >>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc >>> index b86064148fe..e3776fbb543 100644 >>> --- a/gcc/config/aarch64/aarch64.cc >>> +++ b/gcc/config/aarch64/aarch64.cc >>> @@ -749,6 +749,8 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree >>> name, tree, >>> *no_add_attrs = true; >>> return NULL_TREE; >>> >>> + /* Rely on the exclusions list for preserve_none. */ >>> + case ARM_PCS_PRESERVE_NONE: >>> case ARM_PCS_TLSDESC: >>> case ARM_PCS_UNKNOWN: >>> break; >>> @@ -851,6 +853,16 @@ handle_arm_shared (tree *node, tree name, tree args, >>> return NULL_TREE; >>> } >>> >>> +/* Mutually-exclusive function type attributes for various PCS variants. >>> */ >>> +static const struct attribute_spec::exclusions aarch64_pcs_exclusions[] = >>> +{ >>> + /* Attribute name exclusion applies to: >>> + function, type, variable */ >>> + { "aarch64_vector_pcs", false, true, false }, >>> + { "preserve_none", false, true, false }, >>> + { NULL, false, false, false } >>> +}; >>> + >>> /* Mutually-exclusive function type attributes for controlling PSTATE.SM. >>> */ >>> static const struct attribute_spec::exclusions attr_streaming_exclusions[] = >>> { >>> @@ -867,7 +879,10 @@ static const attribute_spec aarch64_gnu_attributes[] = >>> /* { name, min_len, max_len, decl_req, type_req, fn_type_req, >>> affects_type_identity, handler, exclude } */ >>> { "aarch64_vector_pcs", 0, 0, false, true, true, true, >>> - handle_aarch64_vector_pcs_attribute, NULL }, >>> + handle_aarch64_vector_pcs_attribute, >>> + aarch64_pcs_exclusions }, >>> + { "preserve_none", 0, 0, false, true, true, true, NULL, >>> + aarch64_pcs_exclusions }, >>> { "indirect_return", 0, 0, false, true, true, true, NULL, NULL }, >>> { "arm_sve_vector_bits", 1, 1, false, true, false, true, >>> aarch64_sve::handle_arm_sve_vector_bits_attribute, >>> @@ -1317,6 +1332,23 @@ aarch64_sve_abi (void) >>> return sve_abi; >>> } >>> >>> +/* Return the descriptor of the preserve_none PCS. */ >>> + >>> +static const predefined_function_abi & >>> +aarch64_preserve_none_abi (void) >>> +{ >>> + auto &preserve_none_abi = function_abis[ARM_PCS_PRESERVE_NONE]; >>> + if (!preserve_none_abi.initialized_p ()) >>> + { >>> + HARD_REG_SET preserved_regs = {}; >>> + if (!CALL_USED_X18) >>> + SET_HARD_REG_BIT (preserved_regs, R18_REGNUM); >>> + auto full_reg_clobbers = reg_class_contents[ALL_REGS] & >>> ~preserved_regs; >>> + preserve_none_abi.initialize (ARM_PCS_PRESERVE_NONE, >>> full_reg_clobbers); >>> + } >>> + return preserve_none_abi; >>> +} >>> + >>> /* If X is an UNSPEC_SALT_ADDR expression, return the address that it >>> wraps, otherwise return X itself. */ >>> >>> @@ -2312,6 +2344,9 @@ aarch64_fntype_abi (const_tree fntype) >>> if (lookup_attribute ("aarch64_vector_pcs", TYPE_ATTRIBUTES (fntype))) >>> return aarch64_simd_abi (); >>> >>> + if (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (fntype))) >>> + return aarch64_preserve_none_abi (); >>> + >>> if (aarch64_returns_value_in_sve_regs_p (fntype) >>> || aarch64_takes_arguments_in_sve_regs_p (fntype)) >>> return aarch64_sve_abi (); >>> @@ -2519,6 +2554,10 @@ aarch64_reg_save_mode (unsigned int regno) >>> if (FP_REGNUM_P (regno)) >>> switch (crtl->abi->id ()) >>> { >>> + case ARM_PCS_PRESERVE_NONE: >>> + /* In preserve_none all fpr registers are caller saved, so the choice >>> + here should not matter. Nevertheless, fall back to the base AAPCS for >>> + consistency. */ >>> case ARM_PCS_AAPCS64: >>> /* Only the low 64 bits are saved by the base PCS. */ >>> return DFmode; >>> @@ -2649,7 +2688,9 @@ aarch64_hard_regno_call_part_clobbered (unsigned int >>> abi_id, >>> unsigned int regno, >>> machine_mode mode) >>> { >>> - if (FP_REGNUM_P (regno) && abi_id != ARM_PCS_SVE) >>> + if (FP_REGNUM_P (regno) >>> + && abi_id != ARM_PCS_SVE >>> + && abi_id != ARM_PCS_PRESERVE_NONE) >>> { >>> poly_int64 per_register_size = GET_MODE_SIZE (mode); >>> unsigned int nregs = hard_regno_nregs (regno, mode); >>> @@ -6826,6 +6867,10 @@ aarch64_function_ok_for_sibcall (tree, tree exp) >>> auto from_abi = crtl->abi->id (); >>> auto to_abi = expr_callee_abi (exp).id (); >>> >>> + /* preserve_none functions can tail-call anything that the base PCS can. >>> */ >>> + if (from_abi != to_abi && from_abi == ARM_PCS_PRESERVE_NONE) >>> + from_abi = ARM_PCS_AAPCS64; >>> + >>> /* ARM_PCS_SVE preserves strictly more than ARM_PCS_SIMD, which in >>> turn preserves strictly more than the base PCS. The callee must >>> preserve everything that the caller is required to preserve. */ >>> @@ -7287,6 +7332,49 @@ bitint_or_aggr_of_bitint_p (tree type) >>> return false; >>> } >>> >>> +/* How many GPR are available for argument passing in the procedure call >>> + standard. */ >>> +static int >>> +num_pcs_arg_regs (enum arm_pcs pcs) >>> +{ >>> + switch (pcs) >>> + { >>> + case ARM_PCS_PRESERVE_NONE: >>> + return NUM_PRESERVE_NONE_ARG_REGS; >>> + case ARM_PCS_AAPCS64: >>> + case ARM_PCS_SIMD: >>> + case ARM_PCS_SVE: >>> + case ARM_PCS_TLSDESC: >>> + case ARM_PCS_UNKNOWN: >>> + return NUM_ARG_REGS; >>> + } >>> + gcc_unreachable (); >>> +} >>> + >>> +/* Get the NUM'th GPR argument passing register from the PCS procedure call >>> + * standard. */ >>> + >>> +static int >>> +get_pcs_arg_reg (enum arm_pcs pcs, int num) >>> +{ >>> + static const int ARM_PCS_PRESERVE_NONE_REGISTERS[] = >>> PRESERVE_NONE_REGISTERS; >>> + >>> + gcc_assert (num < num_pcs_arg_regs (pcs)); >>> + >>> + switch (pcs) >>> + { >>> + case ARM_PCS_PRESERVE_NONE: >>> + return ARM_PCS_PRESERVE_NONE_REGISTERS[num]; >>> + case ARM_PCS_AAPCS64: >>> + case ARM_PCS_SIMD: >>> + case ARM_PCS_SVE: >>> + case ARM_PCS_TLSDESC: >>> + case ARM_PCS_UNKNOWN: >>> + return R0_REGNUM + num; >>> + } >>> + gcc_unreachable (); >>> +} >>> + >>> /* Layout a function argument according to the AAPCS64 rules. The rule >>> numbers refer to the rule numbers in the AAPCS64. ORIG_MODE is the >>> mode that was originally given to us by the target hook, whereas the >>> @@ -7385,7 +7473,9 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> unprototyped function. There is no ABI-defined location we >>> can return in this case, so we have no real choice but to raise >>> an error immediately, even though this is only a query function. */ >>> - if (arg.named && pcum->pcs_variant != ARM_PCS_SVE) >>> + if (arg.named >>> + && pcum->pcs_variant != ARM_PCS_SVE >>> + && pcum->pcs_variant != ARM_PCS_PRESERVE_NONE) >>> { >>> gcc_assert (!pcum->silent_p); >>> error ("SVE type %qT cannot be passed to an unprototyped function", >>> @@ -7400,7 +7490,6 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> pcum->aapcs_nextnvrn = pcum->aapcs_nvrn + pst_info.num_zr (); >>> pcum->aapcs_nextnprn = pcum->aapcs_nprn + pst_info.num_pr (); >>> gcc_assert (arg.named >>> - && pcum->pcs_variant == ARM_PCS_SVE >>> && pcum->aapcs_nextnvrn <= NUM_FP_ARG_REGS >>> && pcum->aapcs_nextnprn <= NUM_PR_ARG_REGS); >>> pcum->aapcs_reg = pst_info.get_rtx (mode, V0_REGNUM + pcum->aapcs_nvrn, >>> @@ -7514,7 +7603,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> /* C6 - C9. though the sign and zero extension semantics are >>> handled elsewhere. This is the case where the argument fits >>> entirely general registers. */ >>> - if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) >>> + if (allocate_ncrn && (ncrn + nregs <= num_pcs_arg_regs >>> (pcum->pcs_variant))) >>> { >>> gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); >>> >>> @@ -7550,7 +7639,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> inform (input_location, "parameter passing for argument of type " >>> "%qT changed in GCC 9.1", type); >>> ++ncrn; >>> - gcc_assert (ncrn + nregs <= NUM_ARG_REGS); >>> + gcc_assert (ncrn + nregs <= num_pcs_arg_regs (pcum->pcs_variant)); >>> } >>> } >>> >>> @@ -7572,7 +7661,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> if (nregs == 0 >>> || (nregs == 1 && !sve_p) >>> || GET_MODE_CLASS (mode) == MODE_INT) >>> - pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn); >>> + pcum->aapcs_reg >>> + = gen_rtx_REG (mode, get_pcs_arg_reg (pcum->pcs_variant, ncrn)); >>> else >>> { >>> rtx par; >>> @@ -7584,7 +7674,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> scalar_int_mode reg_mode = word_mode; >>> if (nregs == 1) >>> reg_mode = int_mode_for_mode (mode).require (); >>> - rtx tmp = gen_rtx_REG (reg_mode, R0_REGNUM + ncrn + i); >>> + int reg = get_pcs_arg_reg (pcum->pcs_variant, ncrn + i); >>> + rtx tmp = gen_rtx_REG (reg_mode, reg); >>> tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, >>> GEN_INT (i * UNITS_PER_WORD)); >>> XVECEXP (par, 0, i) = tmp; >>> @@ -7597,7 +7688,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> } >>> >>> /* C.11 */ >>> - pcum->aapcs_nextncrn = NUM_ARG_REGS; >>> + pcum->aapcs_nextncrn = num_pcs_arg_regs (pcum->pcs_variant); >>> >>> /* The argument is passed on stack; record the needed number of words for >>> this argument and align the total size if necessary. */ >>> @@ -7675,7 +7766,8 @@ aarch64_function_arg (cumulative_args_t pcum_v, const >>> function_arg_info &arg) >>> CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); >>> gcc_assert (pcum->pcs_variant == ARM_PCS_AAPCS64 >>> || pcum->pcs_variant == ARM_PCS_SIMD >>> - || pcum->pcs_variant == ARM_PCS_SVE); >>> + || pcum->pcs_variant == ARM_PCS_SVE >>> + || pcum->pcs_variant == ARM_PCS_PRESERVE_NONE); >>> >>> if (arg.end_marker_p ()) >>> { >>> @@ -7767,7 +7859,8 @@ aarch64_function_arg_advance (cumulative_args_t >>> pcum_v, >>> CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); >>> if (pcum->pcs_variant == ARM_PCS_AAPCS64 >>> || pcum->pcs_variant == ARM_PCS_SIMD >>> - || pcum->pcs_variant == ARM_PCS_SVE) >>> + || pcum->pcs_variant == ARM_PCS_SVE >>> + || pcum->pcs_variant == ARM_PCS_PRESERVE_NONE) >>> { >>> aarch64_layout_arg (pcum_v, arg); >>> gcc_assert ((pcum->aapcs_reg != NULL_RTX) >>> @@ -7786,13 +7879,41 @@ aarch64_function_arg_advance (cumulative_args_t >>> pcum_v, >>> } >>> } >>> >>> -bool >>> -aarch64_function_arg_regno_p (unsigned regno) >>> +/* Checks if a register is live at entry of a preserve_none pcs function. >>> + That is, it used for passing registers. See >>> ARM_PCS_PRESERVE_NONE_REGISTERS >>> + for full list and order of argument passing registers. */ >>> + >>> +static bool >>> +function_arg_preserve_none_regno_p (unsigned regno) >>> { >>> - return ((GP_REGNUM_P (regno) && regno < R0_REGNUM + NUM_ARG_REGS) >>> + return ((GP_REGNUM_P (regno) && regno != R8_REGNUM && regno != R15_REGNUM >>> + && regno != R16_REGNUM && regno != R17_REGNUM && regno != R18_REGNUM >>> + && regno != R19_REGNUM && regno != R29_REGNUM && regno != R30_REGNUM) >>> || (FP_REGNUM_P (regno) && regno < V0_REGNUM + NUM_FP_ARG_REGS) >>> || (PR_REGNUM_P (regno) && regno < P0_REGNUM + NUM_PR_ARG_REGS)); >>> } >>> +/* Implements FUNCTION_ARG_REGNO_P. */ >>> +bool >>> +aarch64_function_arg_regno_p (unsigned regno) >>> +{ >>> + enum arm_pcs pcs >>> + = cfun ? (arm_pcs) fndecl_abi (cfun->decl).id () : ARM_PCS_AAPCS64; >>> + >>> + switch (pcs) >>> + { >>> + case ARM_PCS_AAPCS64: >>> + case ARM_PCS_SIMD: >>> + case ARM_PCS_SVE: >>> + case ARM_PCS_TLSDESC: >>> + case ARM_PCS_UNKNOWN: >>> + return ((GP_REGNUM_P (regno) && regno < R0_REGNUM + NUM_ARG_REGS) >>> + || (FP_REGNUM_P (regno) && regno < V0_REGNUM + NUM_FP_ARG_REGS) >>> + || (PR_REGNUM_P (regno) && regno < P0_REGNUM + NUM_PR_ARG_REGS)); >>> + case ARM_PCS_PRESERVE_NONE: >>> + return function_arg_preserve_none_regno_p (regno); >>> + } >>> + gcc_unreachable (); >>> +} >>> >>> /* Implement FUNCTION_ARG_BOUNDARY. Every parameter gets at least >>> PARM_BOUNDARY bits of alignment, but will be given anything up >>> @@ -21804,8 +21925,9 @@ aarch64_expand_builtin_va_start (tree valist, rtx >>> nextarg ATTRIBUTE_UNUSED) >>> >>> cum = &crtl->args.info; >>> if (cfun->va_list_gpr_size) >>> - gr_save_area_size = MIN ((NUM_ARG_REGS - cum->aapcs_ncrn) * >>> UNITS_PER_WORD, >>> - cfun->va_list_gpr_size); >>> + gr_save_area_size = MIN ((num_pcs_arg_regs (cum->pcs_variant) >>> + - cum->aapcs_ncrn) >>> + * UNITS_PER_WORD, cfun->va_list_gpr_size); >>> if (cfun->va_list_fpr_size) >>> vr_save_area_size = MIN ((NUM_FP_ARG_REGS - cum->aapcs_nvrn) >>> * UNITS_PER_VREG, cfun->va_list_fpr_size); >>> @@ -22190,7 +22312,8 @@ aarch64_setup_incoming_varargs (cumulative_args_t >>> cum_v, >>> /* Found out how many registers we need to save. >>> Honor tree-stdvar analysis results. */ >>> if (cfun->va_list_gpr_size) >>> - gr_saved = MIN (NUM_ARG_REGS - local_cum.aapcs_ncrn, >>> + gr_saved = MIN (num_pcs_arg_regs (local_cum.pcs_variant) >>> + - local_cum.aapcs_ncrn, >>> cfun->va_list_gpr_size / UNITS_PER_WORD); >>> if (cfun->va_list_fpr_size) >>> vr_saved = MIN (NUM_FP_ARG_REGS - local_cum.aapcs_nvrn, >>> @@ -22214,8 +22337,22 @@ aarch64_setup_incoming_varargs (cumulative_args_t >>> cum_v, >>> mem = gen_frame_mem (BLKmode, ptr); >>> set_mem_alias_set (mem, get_varargs_alias_set ()); >>> >>> - move_block_from_reg (local_cum.aapcs_ncrn + R0_REGNUM, >>> - mem, gr_saved); >>> + /* For preserve_none pcs we can't use move_block_from_reg as the >>> + argument passing register order is not consecutive. */ >>> + if (local_cum.pcs_variant == ARM_PCS_PRESERVE_NONE) >>> + { >>> + for (int i = 0; i < gr_saved; ++i) >>> + { >>> + rtx tem = operand_subword (mem, i, 1, BLKmode); >>> + gcc_assert (tem); >>> + int reg = get_pcs_arg_reg (local_cum.pcs_variant, >>> + local_cum.aapcs_ncrn + i); >>> + emit_move_insn (tem, gen_rtx_REG (word_mode, reg)); >>> + } >>> + } >>> + else >>> + move_block_from_reg (R0_REGNUM + local_cum.aapcs_ncrn, mem, >>> + gr_saved); >>> } >>> if (vr_saved > 0) >>> { >>> @@ -25521,7 +25658,7 @@ 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) >>> + if (pcs == ARM_PCS_SIMD || pcs == ARM_PCS_SVE || pcs == >>> ARM_PCS_PRESERVE_NONE) >>> return true; >>> >>> /* Check for ABIs that allow PSTATE.SM to be 1 on entry. */ >>> @@ -30252,6 +30389,8 @@ aarch64_comp_type_attributes (const_tree type1, >>> const_tree type2) >>> >>> if (!check_attr ("gnu", "aarch64_vector_pcs")) >>> return 0; >>> + if (!check_attr ("gnu", "preserve_none")) >>> + return 0; >>> if (!check_attr ("gnu", "indirect_return")) >>> return 0; >>> if (!check_attr ("gnu", "Advanced SIMD type")) >>> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h >>> index 2cd929d83f9..0e596b59744 100644 >>> --- a/gcc/config/aarch64/aarch64.h >>> +++ b/gcc/config/aarch64/aarch64.h >>> @@ -696,6 +696,31 @@ through +ssve-fp8dot2. */ >>> #define NUM_FP_ARG_REGS 8 >>> #define NUM_PR_ARG_REGS 4 >>> >>> +/* The argument passing regs for preserve_none pcs. */ >>> +#if TARGET_AARCH64_MS_ABI >>> +#define NUM_PRESERVE_NONE_ARG_REGS 23 >>> +#define PRESERVE_NONE_REGISTERS \ >>> +{ \ >>> + R20_REGNUM, R21_REGNUM, R22_REGNUM, R23_REGNUM, R24_REGNUM, R25_REGNUM,\ >>> + R26_REGNUM, R27_REGNUM, R28_REGNUM,\ >>> + R0_REGNUM, R1_REGNUM, R2_REGNUM, R3_REGNUM, R4_REGNUM, R5_REGNUM,\ >>> + R6_REGNUM, R7_REGNUM,\ >>> + R10_REGNUM, R11_REGNUM, R12_REGNUM, R13_REGNUM, R14_REGNUM, R9_REGNUM\ >>> +} >>> +#else >>> +#define NUM_PRESERVE_NONE_ARG_REGS 24 >>> +#define PRESERVE_NONE_REGISTERS \ >>> +{ \ >>> + R20_REGNUM, R21_REGNUM, R22_REGNUM, R23_REGNUM, R24_REGNUM, R25_REGNUM,\ >>> + R26_REGNUM, R27_REGNUM, R28_REGNUM,\ >>> + R0_REGNUM, R1_REGNUM, R2_REGNUM, R3_REGNUM, R4_REGNUM, R5_REGNUM,\ >>> + R6_REGNUM, R7_REGNUM,\ >>> + R10_REGNUM, R11_REGNUM, R12_REGNUM, R13_REGNUM, R14_REGNUM, R9_REGNUM,\ >>> + R15_REGNUM\ >>> +} >>> +#endif >>> + >>> + >>> /* A Homogeneous Floating-Point or Short-Vector Aggregate may have at most >>> four members. */ >>> #define HA_MAX_NUM_FLDS 4 >>> @@ -1150,6 +1175,8 @@ enum arm_pcs >>> ARM_PCS_SVE, /* For functions that pass or return >>> values in SVE registers. */ >>> ARM_PCS_TLSDESC, /* For targets of tlsdesc calls. */ >>> + ARM_PCS_PRESERVE_NONE, /* PCS variant with no call-preserved >>> + registers except X29. */ >>> ARM_PCS_UNKNOWN >>> }; >>> >>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi >>> index fb117f59665..4e906c2d7a2 100644 >>> --- a/gcc/doc/extend.texi >>> +++ b/gcc/doc/extend.texi >>> @@ -3930,6 +3930,27 @@ threads, such as the POSIX @code{swapcontext} >>> function. This attribute >>> adds a @code{BTI J} instruction when BTI is enabled e.g. via >>> @option{-mbranch-protection}. >>> >>> +@cindex @code{preserve_none} function attribute, AArch64 >>> +@item preserve_none >>> +Use this attribute to change the procedure call standard of the specified >>> +function to the preserve-none variant. >>> + >>> +The preserve-none ABI variant modifies the AAPCS such that has no >>> callee-saved >>> +registers (including SIMD and floating-point registers). That is, with the >>> +exception of the stack register, link register (r30), and frame pointer >>> (r29), >>> +all registers are caller saved, and can be used as scratch registers by the >>> +callee. >>> + >>> +Additionally, registers r20--r28, r0--r7, r10--r14, r9 and r15 are used for >>> +argument passing, in that order. For Microsoft Windows targets >>> +r15 is not used for argument passing. >>> + >>> +The return value registers remain r0 and r1 in both cases. >>> + >>> +All other details are the same as for the AAPCS ABI. >>> + >>> +This ABI has not been stabilized, and may be subject to change in future >>> +versions. >>> @end table >>> >>> The above target attributes can be specified as follows: >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_1.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_1.c >>> new file mode 100644 >>> index 00000000000..1390173836d >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_1.c >>> @@ -0,0 +1,143 @@ >>> +/* { dg-do compile } */ >>> +/* { dg-options "-O2 -fno-schedule-insns2" } */ >>> +/* { dg-final { check-function-bodies "**" "" "" } } */ >>> +/* { dg-skip-if "" { *-*-mingw* } } */ >>> + >>> +void normal_callee(); >>> +void preserve_none_callee() [[gnu::preserve_none]]; >>> + >>> +#pragma GCC target "+sve" >>> + >>> +/* >>> +** preserve_none_caller1: >>> +** ?#APP >>> +** nop >>> +** ?#NO_APP >>> +** ret >>> +*/ >>> +void preserve_none_caller1() [[gnu::preserve_none]] >>> +{ >>> + asm volatile ("nop" ::: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", >>> + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", >>> + "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", >>> + "x24", "x25", "x26", "x27", "x28", >>> + >>> + "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", >>> + "z8", "z9", "z10", "z11", "z12", "z13", "z14", "z15", >>> + "z16", "z17", "z18", "z19", "z20", "z21", "z22", "z23", >>> + "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31", >>> + >>> + "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", >>> + "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"); >>> +} >>> + >>> +/* >>> +** preserve_none_caller2: >>> +** stp x29, x30, \[sp, #?-16\]! >>> +** mov x29, sp >>> +** bl normal_callee >>> +** mov w0, w20 >>> +** ldp x29, x30, \[sp\], #?16 >>> +** ret >>> +*/ >>> +int preserve_none_caller2(int x) [[gnu::preserve_none]] >>> +{ >>> + normal_callee(); >>> + return x; >>> +} >>> + >>> +/* >>> +** preserve_none_caller3: >>> +** stp x29, x30, \[sp, #?-32\]! >>> +** mov x29, sp >>> +** str w20, \[sp, #?[0-9]+\] >>> +** bl preserve_none_callee >>> +** ldr w0, \[sp, #?[0-9]+\] >>> +** ldp x29, x30, \[sp\], #?32 >>> +** ret >>> +*/ >>> +int preserve_none_caller3(int x) [[gnu::preserve_none]] >>> +{ >>> + preserve_none_callee(); >>> + return x; >>> +} >>> + >>> +/* >>> +** preserve_none_caller4: >>> +** b preserve_none_callee >>> +*/ >>> +void preserve_none_caller4() [[gnu::preserve_none]] >>> +{ >>> + preserve_none_callee(); >>> +} >>> + >>> +/* >>> +** preserve_none_caller5: >>> +** b preserve_none_callee >>> +*/ >>> +void preserve_none_caller5(__SVBool_t x) [[gnu::preserve_none]] >>> +{ >>> + preserve_none_callee(); >>> +} >>> + >>> +/* >>> +** normal_caller1: >>> +** stp x29, x30, \[sp, #?-160\]! >>> +** mov x29, sp >>> +** stp x19, x20, \[sp, #?16\] >>> +** stp x21, x22, \[sp, #?32\] >>> +** stp x23, x24, \[sp, #?48\] >>> +** stp x25, x26, \[sp, #?64\] >>> +** stp x27, x28, \[sp, #?80\] >>> +** stp d8, d9, \[sp, #?96\] >>> +** stp d10, d11, \[sp, #?112\] >>> +** stp d12, d13, \[sp, #?128\] >>> +** stp d14, d15, \[sp, #?144\] >>> +** bl preserve_none_callee >>> +** ldp d8, d9, \[sp, #?96\] >>> +** ldp d10, d11, \[sp, #?112\] >>> +** ldp d12, d13, \[sp, #?128\] >>> +** ldp d14, d15, \[sp, #?144\] >>> +** ldp x19, x20, \[sp, #?16\] >>> +** ldp x21, x22, \[sp, #?32\] >>> +** ldp x23, x24, \[sp, #?48\] >>> +** ldp x25, x26, \[sp, #?64\] >>> +** ldp x27, x28, \[sp, #?80\] >>> +** ldp x29, x30, \[sp\], #?160 >>> +** ret >>> +*/ >>> +void normal_caller1() >>> +{ >>> + preserve_none_callee(); >>> +} >>> + >>> +/* >>> +** normal_caller2: >>> +** stp x29, x30, \[sp, #?-160\]! >>> +** mov x29, sp >>> +** stp x19, x20, \[sp, #?16\] >>> +** stp x21, x22, \[sp, #?32\] >>> +** stp x23, x24, \[sp, #?48\] >>> +** stp x25, x26, \[sp, #?64\] >>> +** stp x27, x28, \[sp, #?80\] >>> +** stp d8, d9, \[sp, #?96\] >>> +** stp d10, d11, \[sp, #?112\] >>> +** stp d12, d13, \[sp, #?128\] >>> +** stp d14, d15, \[sp, #?144\] >>> +** blr x0 >>> +** ldp d8, d9, \[sp, #?96\] >>> +** ldp d10, d11, \[sp, #?112\] >>> +** ldp d12, d13, \[sp, #?128\] >>> +** ldp d14, d15, \[sp, #?144\] >>> +** ldp x19, x20, \[sp, #?16\] >>> +** ldp x21, x22, \[sp, #?32\] >>> +** ldp x23, x24, \[sp, #?48\] >>> +** ldp x25, x26, \[sp, #?64\] >>> +** ldp x27, x28, \[sp, #?80\] >>> +** ldp x29, x30, \[sp\], #?160 >>> +** ret >>> +*/ >>> +void normal_caller2(void (*callee)() [[gnu::preserve_none]]) >>> +{ >>> + callee(); >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_2.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_2.c >>> new file mode 100644 >>> index 00000000000..1bb89e026e5 >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_2.c >>> @@ -0,0 +1,49 @@ >>> +/* { dg-options "" } */ >>> + >>> +void multi1() [[gnu::aarch64_vector_pcs, gnu::preserve_none]]; /* { >>> dg-warning {ignoring attribute 'preserve_none' because it conflicts} } */ >>> +void multi2() [[gnu::preserve_none, gnu::aarch64_vector_pcs]]; /* { >>> dg-warning {ignoring attribute 'aarch64_vector_pcs' because it conflicts} } >>> */ >>> + >>> +void normal_callee(); >>> +void preserve_none_callee() [[gnu::preserve_none]]; >>> +void vector_callee() [[gnu::aarch64_vector_pcs]]; >>> +void sve_callee(__SVBool_t); >>> +void sve_preserve_none_callee(__SVBool_t) [[gnu::preserve_none]]; >>> + >>> +void (*normal_ptr)(); >>> +void (*preserve_none_ptr)() [[gnu::preserve_none]]; >>> +void (*vector_ptr)() [[gnu::aarch64_vector_pcs]]; >>> +void (*sve_ptr)(__SVBool_t); >>> +void (*sve_preserve_none_ptr)(__SVBool_t) [[gnu::preserve_none]]; >>> + >>> +void f() >>> +{ >>> + normal_ptr = normal_callee; >>> + normal_ptr = preserve_none_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + normal_ptr = vector_callee; /* { dg-error {incompatible pointer type} } >>> */ >>> + normal_ptr = sve_callee; /* { dg-error {incompatible pointer type} } */ >>> + normal_ptr = sve_preserve_none_callee; /* { dg-error {incompatible >>> pointer type} } */ >>> + >>> + preserve_none_ptr = normal_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + preserve_none_ptr = preserve_none_callee; >>> + preserve_none_ptr = vector_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + preserve_none_ptr = sve_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + preserve_none_ptr = sve_preserve_none_callee; /* { dg-error >>> {incompatible pointer type} } */ >>> + >>> + vector_ptr = normal_callee; /* { dg-error {incompatible pointer type} } >>> */ >>> + vector_ptr = preserve_none_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + vector_ptr = vector_callee; >>> + vector_ptr = sve_callee; /* { dg-error {incompatible pointer type} } */ >>> + vector_ptr = sve_preserve_none_callee; /* { dg-error {incompatible >>> pointer type} } */ >>> + >>> + sve_ptr = normal_callee; /* { dg-error {incompatible pointer type} } */ >>> + sve_ptr = preserve_none_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + sve_ptr = vector_callee; /* { dg-error {incompatible pointer type} } */ >>> + sve_ptr = sve_callee; >>> + sve_ptr = sve_preserve_none_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + >>> + sve_preserve_none_ptr = normal_callee; /* { dg-error {incompatible >>> pointer type} } */ >>> + sve_preserve_none_ptr = preserve_none_callee; /* { dg-error >>> {incompatible pointer type} } */ >>> + sve_preserve_none_ptr = vector_callee; /* { dg-error {incompatible >>> pointer type} } */ >>> + sve_preserve_none_ptr = sve_callee; /* { dg-error {incompatible pointer >>> type} } */ >>> + sve_preserve_none_ptr = sve_preserve_none_callee; >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_3.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_3.c >>> new file mode 100644 >>> index 00000000000..0258177f422 >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_3.c >>> @@ -0,0 +1,114 @@ >>> +/* { dg-do run } */ >>> +/* { dg-options "-O2 -std=gnu23" } */ >>> + >>> +int no_arg_stack_use_callee >>> + [[gnu::preserve_none, gnu::noinline, >>> + gnu::noipa]] (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, int a13, >>> + int a14, int a15, int a16, int a17, int a18, int a19, int a20, >>> + int a21, int a22, int a23) >>> +{ >>> + /* Clobber all the registers to check they are correctly marked live at >>> the >>> + start. */ >>> + asm volatile("mov x0, #0;" >>> + "mov x1, #0;" >>> + "mov x2, #0;" >>> + "mov x3, #0;" >>> + "mov x4, #0;" >>> + "mov x5, #0;" >>> + "mov x6, #0;" >>> + "mov x7, #0;" >>> + "mov x8, #0;" >>> + "mov x9, #0;" >>> + "mov x10, #0;" >>> + "mov x11, #0;" >>> + "mov x12, #0;" >>> + "mov x13, #0;" >>> + "mov x14, #0;" >>> + "mov x15, #0;" >>> + "mov x16, #0;" >>> + "mov x17, #0;" >>> + "mov x18, #0;" >>> + "mov x19, #0;" >>> + "mov x20, #0;" >>> + "mov x21, #0;" >>> + "mov x22, #0;" >>> + "mov x23, #0;" >>> + "mov x24, #0;" >>> + "mov x25, #0;" >>> + "mov x26, #0;" >>> + "mov x27, #0;" >>> + "mov x28, #0;" :: >>> + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", >>> + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", >>> + "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", >>> + "x26", "x27", "x28"); >>> + >>> + return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 >>> + a13 >>> + + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23; >>> +} >>> + >>> +int arg_stack_use_callee >>> + [[gnu::preserve_none, gnu::noinline, >>> + gnu::noipa]] (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, int a13, >>> + int a14, int a15, int a16, int a17, int a18, int a19, int a20, >>> + int a21, int a22, int a23, int a24) >>> +{ >>> + /* Clobber all the registers to check they are correctly marked live at >>> the >>> + start. */ >>> + asm volatile("mov x0, #0;" >>> + "mov x1, #0;" >>> + "mov x2, #0;" >>> + "mov x3, #0;" >>> + "mov x4, #0;" >>> + "mov x5, #0;" >>> + "mov x6, #0;" >>> + "mov x7, #0;" >>> + "mov x8, #0;" >>> + "mov x9, #0;" >>> + "mov x10, #0;" >>> + "mov x11, #0;" >>> + "mov x12, #0;" >>> + "mov x13, #0;" >>> + "mov x14, #0;" >>> + "mov x15, #0;" >>> + "mov x16, #0;" >>> + "mov x17, #0;" >>> + "mov x18, #0;" >>> + "mov x19, #0;" >>> + "mov x20, #0;" >>> + "mov x21, #0;" >>> + "mov x22, #0;" >>> + "mov x23, #0;" >>> + "mov x24, #0;" >>> + "mov x25, #0;" >>> + "mov x26, #0;" >>> + "mov x27, #0;" >>> + "mov x28, #0;" :: >>> + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", >>> + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", >>> + "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", >>> + "x26", "x27", "x28"); >>> + >>> + return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 >>> + a13 >>> + + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24; >>> +} >>> + >>> +int >>> +main () >>> +{ >>> + int res = no_arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, >>> 12, >>> + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); >>> + >>> + if (res != 23 * 24 / 2) >>> + return 1; >>> + >>> + res = arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, >>> 13, 14, >>> + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24); >>> + >>> + if (res != 24 * 25 / 2) >>> + return 1; >>> + >>> + return 0; >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_4.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_4.c >>> new file mode 100644 >>> index 00000000000..fc8347d6c28 >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_4.c >>> @@ -0,0 +1,99 @@ >>> +/* { dg-do compile } */ >>> +/* { dg-options "-O2 -fno-schedule-insns2" } */ >>> +/* { dg-final { check-function-bodies "**" "" "" } } */ >>> +/* { dg-skip-if "" { *-*-mingw* } } */ >>> + >>> +int no_arg_stack_use_callee >>> + [[gnu::preserve_none, gnu::noinline, >>> + gnu::noipa]] (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, int a13, >>> + int a14, int a15, int a16, int a17, int a18, int a19, int a20, >>> + int a21, int a22, int a24); >>> + >>> +/* Check the pcs argument order is correct. Should be x20-28, x0-7, >>> x10-14, x9, >>> + * x15 and that the return arg is x0 */ >>> + >>> +/* >>> +** no_arg_stack_use_caller: >>> +** ... >>> +** mov w15, 23 >>> +** mov w9, 22 >>> +** mov w14, 21 >>> +** mov w13, 20 >>> +** mov w12, 19 >>> +** mov w11, 18 >>> +** mov w10, 17 >>> +** mov w7, 16 >>> +** mov w6, 15 >>> +** mov w5, 14 >>> +** mov w4, 13 >>> +** mov w3, 12 >>> +** mov w2, 11 >>> +** mov w1, 10 >>> +** mov w0, 9 >>> +** mov w28, 8 >>> +** mov w27, 7 >>> +** mov w26, 6 >>> +** mov w25, 5 >>> +** mov w24, 4 >>> +** mov w23, 3 >>> +** mov w22, 2 >>> +** mov w21, 1 >>> +** mov w20, 0 >>> +** bl no_arg_stack_use_callee >>> +** add w0, w0, 1 >>> +** ... >>> +*/ >>> +int no_arg_stack_use_caller [[gnu::preserve_none]] () >>> +{ >>> + return no_arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, >>> 12, 13, >>> + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) >>> + + 1; >>> +} >>> + >>> +int arg_stack_use_callee >>> + [[gnu::preserve_none, gnu::noinline, >>> + gnu::noipa]] (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, int a13, >>> + int a14, int a15, int a16, int a17, int a18, int a19, int a20, >>> + int a21, int a22, int a23, int a24); >>> + >>> +/* >>> +** arg_stack_use_caller: >>> +** ... >>> +** mov w0, 24 >>> +** mov w15, 23 >>> +** mov w9, 22 >>> +** mov w14, 21 >>> +** mov w13, 20 >>> +** mov w12, 19 >>> +** mov w11, 18 >>> +** mov w10, 17 >>> +** mov w7, 16 >>> +** mov w6, 15 >>> +** mov w5, 14 >>> +** mov w4, 13 >>> +** mov w3, 12 >>> +** mov w2, 11 >>> +** mov w1, 10 >>> +** mov w28, 8 >>> +** mov w27, 7 >>> +** mov w26, 6 >>> +** mov w25, 5 >>> +** mov w24, 4 >>> +** mov w23, 3 >>> +** mov w22, 2 >>> +** mov w21, 1 >>> +** mov w20, 0 >>> +** str w0, \[sp\] >>> +** mov w0, 9 >>> +** bl arg_stack_use_callee >>> +** add w0, w0, 1 >>> +** ... >>> +*/ >>> +int arg_stack_use_caller [[gnu::preserve_none]] () >>> +{ >>> + return arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, >>> 13, 14, >>> + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) >>> + + 1; >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_5.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_5.c >>> new file mode 100644 >>> index 00000000000..d11bf10a898 >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_5.c >>> @@ -0,0 +1,47 @@ >>> +/* { dg-do compile } */ >>> +/* { dg-options "-O2 -fno-schedule-insns2" } */ >>> +/* { dg-final { check-function-bodies "**" "" "" } } */ >>> +/* { dg-skip-if "" { *-*-mingw* } } */ >>> + >>> +#include <stdarg.h> >>> +int foo [[gnu::preserve_none]] (...); >>> + >>> +/* Check the pcs argument order is correct. Should be x20-28, x0-7, >>> x10-14, x9, x15 and that the return arg is x0 */ >>> + >>> +/* >>> +** bar: >>> +** ... >>> +** mov w15, 23 >>> +** mov w9, 22 >>> +** mov w14, 21 >>> +** mov w13, 20 >>> +** mov w12, 19 >>> +** mov w11, 18 >>> +** mov w10, 17 >>> +** mov w7, 16 >>> +** mov w6, 15 >>> +** mov w5, 14 >>> +** mov w4, 13 >>> +** mov w3, 12 >>> +** mov w2, 11 >>> +** mov w1, 10 >>> +** mov w0, 9 >>> +** mov w28, 8 >>> +** mov w27, 7 >>> +** mov w26, 6 >>> +** mov w25, 5 >>> +** mov w24, 4 >>> +** mov w23, 3 >>> +** mov w22, 2 >>> +** mov w21, 1 >>> +** mov w20, 0 >>> +** bl foo >>> +** add w0, w0, 1 >>> +** ... >>> +*/ >>> +int bar [[gnu::preserve_none]] () >>> +{ >>> + return foo (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, >>> 17, 18, >>> + 19, 20, 21, 22, 23) >>> + + 1; >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_6.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_6.c >>> new file mode 100644 >>> index 00000000000..687e30a063e >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_6.c >>> @@ -0,0 +1,76 @@ >>> +/* { dg-do run } */ >>> +/* { dg-options "-O2 -std=gnu23" } */ >>> + >>> +#include <stdarg.h> >>> +#include <stdio.h> >>> + >>> +int preserve_none_va_func >>> + [[gnu::preserve_none, gnu::noinline, gnu::noclone]] (int count, ...) >>> +{ >>> + asm volatile("mov x0, #0;" >>> + "mov x1, #0;" >>> + "mov x2, #0;" >>> + "mov x3, #0;" >>> + "mov x4, #0;" >>> + "mov x5, #0;" >>> + "mov x6, #0;" >>> + "mov x7, #0;" >>> + "mov x8, #0;" >>> + "mov x9, #0;" >>> + "mov x10, #0;" >>> + "mov x11, #0;" >>> + "mov x12, #0;" >>> + "mov x13, #0;" >>> + "mov x14, #0;" >>> + "mov x15, #0;" >>> + "mov x16, #0;" >>> + "mov x17, #0;" >>> + "mov x18, #0;" >>> + "mov x19, #0;" >>> + "mov x20, #0;" >>> + "mov x21, #0;" >>> + "mov x22, #0;" >>> + "mov x23, #0;" >>> + "mov x24, #0;" >>> + "mov x25, #0;" >>> + "mov x26, #0;" >>> + "mov x27, #0;" >>> + "mov x28, #0;" :: >>> + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", >>> + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", >>> + "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", >>> + "x26", "x27", "x28"); >>> + >>> + int sum = 0; >>> + >>> + va_list args; >>> + >>> + va_start (args, count); >>> + for (int i = 0; i < count; i++) >>> + sum += va_arg (args, int); >>> + va_end (args); >>> + >>> + return sum; >>> +} >>> + >>> +int >>> +main () >>> +{ >>> + int res = preserve_none_va_func (23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, >>> 11, 12, >>> + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22); >>> + if (res != 23 * 22 / 2) >>> + return 1; >>> + >>> + res = preserve_none_va_func (24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, >>> 12, 13, >>> + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); >>> + >>> + if (res != 24 * 23 / 2) >>> + return 1; >>> + >>> + res = preserve_none_va_func (25, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, >>> 12, 13, >>> + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24); >>> + if (res != 25 * 24 / 2) >>> + return 1; >>> + >>> + return 0; >>> +} >>> diff --git a/gcc/testsuite/gcc.target/aarch64/preserve_none_mingw_1.c >>> b/gcc/testsuite/gcc.target/aarch64/preserve_none_mingw_1.c >>> new file mode 100644 >>> index 00000000000..11703c8bb96 >>> --- /dev/null >>> +++ b/gcc/testsuite/gcc.target/aarch64/preserve_none_mingw_1.c >>> @@ -0,0 +1,93 @@ >>> +/* { dg-do compile { target aarch64*-*-mingw* } } */ >>> +/* { dg-options "-O2 -fno-schedule-insns2" } */ >>> +/* { dg-final { check-function-bodies "**" "" "" } } */ >>> + >>> +int no_arg_stack_use_callee [[gnu::preserve_none, gnu::noinline, >>> gnu::noipa]] >>> + (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, >>> + int a13, int a14, int a15, int a16, int a17, int a18, >>> + int a19, int a20, int a21, int a22); >>> + >>> +/* Check the pcs argument order is correct. Should be x20-28, x0-7, >>> x10-14, x9, and that the return arg is x0 */ >>> + >>> +/* >>> +** no_arg_stack_use_caller: >>> +** ... >>> +** mov w9, 22 >>> +** mov w14, 21 >>> +** mov w13, 20 >>> +** mov w12, 19 >>> +** mov w11, 18 >>> +** mov w10, 17 >>> +** mov w7, 16 >>> +** mov w6, 15 >>> +** mov w5, 14 >>> +** mov w4, 13 >>> +** mov w3, 12 >>> +** mov w2, 11 >>> +** mov w1, 10 >>> +** mov w0, 9 >>> +** mov w28, 8 >>> +** mov w27, 7 >>> +** mov w26, 6 >>> +** mov w25, 5 >>> +** mov w24, 4 >>> +** mov w23, 3 >>> +** mov w22, 2 >>> +** mov w21, 1 >>> +** mov w20, 0 >>> +** bl no_arg_stack_use_callee >>> +** add w0, w0, 1 >>> +** ... >>> +*/ >>> +int no_arg_stack_use_caller [[gnu::preserve_none]] () >>> +{ >>> + return no_arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, >>> 12, 13, >>> + 14, 15, 16, 17, 18, 19, 20, 21, 22) >>> + + 1; >>> +} >>> + >>> +int arg_stack_use_callee [[gnu::preserve_none, gnu::noinline, gnu::noipa]] >>> + (int a0, int a1, int a2, int a3, int a4, int a5, int a6, >>> + int a7, int a8, int a9, int a10, int a11, int a12, >>> + int a13, int a14, int a15, int a16, int a17, int a18, >>> + int a19, int a20, int a21, int a22, int a23); >>> + >>> +/* >>> +** arg_stack_use_caller: >>> +** ... >>> +** mov w0, 23 >>> +** mov w9, 22 >>> +** mov w14, 21 >>> +** mov w13, 20 >>> +** mov w12, 19 >>> +** mov w11, 18 >>> +** mov w10, 17 >>> +** mov w7, 16 >>> +** mov w6, 15 >>> +** mov w5, 14 >>> +** mov w4, 13 >>> +** mov w3, 12 >>> +** mov w2, 11 >>> +** mov w1, 10 >>> +** mov w28, 8 >>> +** mov w27, 7 >>> +** mov w26, 6 >>> +** mov w25, 5 >>> +** mov w24, 4 >>> +** mov w23, 3 >>> +** mov w22, 2 >>> +** mov w21, 1 >>> +** mov w20, 0 >>> +** str w0, \[sp\] >>> +** mov w0, 9 >>> +** bl arg_stack_use_callee >>> +** add w0, w0, 1 >>> +** ... >>> +*/ >>> +int arg_stack_use_caller [[gnu::preserve_none]] () >>> +{ >>> + return arg_stack_use_callee (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, >>> 13, 14, >>> + 15, 16, 17, 18, 19, 20, 21, 22, 23) >>> + + 1; >>> +} >>> -- >>> 2.34.1 >>> >> > > -- > Alfie Richards
