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